1 /*
2  * Copyright 2016 Federico Tomassetti
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.github.javaparser.symbolsolver.javaparsermodel.contexts;
18 
19 import com.github.javaparser.ast.expr.Expression;
20 import com.github.javaparser.ast.expr.FieldAccessExpr;
21 import com.github.javaparser.ast.expr.ThisExpr;
22 import com.github.javaparser.resolution.declarations.*;
23 import com.github.javaparser.resolution.types.ResolvedPrimitiveType;
24 import com.github.javaparser.resolution.types.ResolvedType;
25 import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade;
26 import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFactory;
27 import com.github.javaparser.symbolsolver.model.resolution.SymbolReference;
28 import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
29 import com.github.javaparser.symbolsolver.model.resolution.Value;
30 import com.github.javaparser.symbolsolver.resolution.SymbolSolver;
31 
32 import java.util.Collection;
33 import java.util.List;
34 import java.util.Optional;
35 
36 import static com.github.javaparser.symbolsolver.javaparser.Navigator.requireParentNode;
37 
38 /**
39  * @author Federico Tomassetti
40  */
41 public class FieldAccessContext extends AbstractJavaParserContext<FieldAccessExpr> {
42 
43     private static final String ARRAY_LENGTH_FIELD_NAME = "length";
44 
FieldAccessContext(FieldAccessExpr wrappedNode, TypeSolver typeSolver)45     public FieldAccessContext(FieldAccessExpr wrappedNode, TypeSolver typeSolver) {
46         super(wrappedNode, typeSolver);
47     }
48 
49     @Override
solveSymbol(String name)50     public SymbolReference<? extends ResolvedValueDeclaration> solveSymbol(String name) {
51         if (wrappedNode.getName().toString().equals(name)) {
52             if (wrappedNode.getScope() instanceof ThisExpr) {
53                 ResolvedType typeOfThis = JavaParserFacade.get(typeSolver).getTypeOfThisIn(wrappedNode);
54                 return new SymbolSolver(typeSolver).solveSymbolInType(typeOfThis.asReferenceType().getTypeDeclaration(), name);
55             }
56         }
57         return JavaParserFactory.getContext(requireParentNode(wrappedNode), typeSolver).solveSymbol(name);
58     }
59 
60     @Override
solveType(String name)61     public SymbolReference<ResolvedTypeDeclaration> solveType(String name) {
62         return JavaParserFactory.getContext(requireParentNode(wrappedNode), typeSolver).solveType(name);
63     }
64 
65     @Override
solveMethod(String name, List<ResolvedType> parameterTypes, boolean staticOnly)66     public SymbolReference<ResolvedMethodDeclaration> solveMethod(String name, List<ResolvedType> parameterTypes, boolean staticOnly) {
67         return JavaParserFactory.getContext(requireParentNode(wrappedNode), typeSolver).solveMethod(name, parameterTypes, false);
68     }
69 
70     @Override
solveSymbolAsValue(String name)71     public Optional<Value> solveSymbolAsValue(String name) {
72         Expression scope = wrappedNode.getScope();
73         if (wrappedNode.getName().toString().equals(name)) {
74             ResolvedType typeOfScope = JavaParserFacade.get(typeSolver).getType(scope);
75             if (typeOfScope.isArray() && name.equals(ARRAY_LENGTH_FIELD_NAME)) {
76                 return Optional.of(new Value(ResolvedPrimitiveType.INT, ARRAY_LENGTH_FIELD_NAME));
77             }
78             if (typeOfScope.isReferenceType()) {
79                 if (typeOfScope.asReferenceType().getTypeDeclaration().isEnum()) {
80                     ResolvedEnumDeclaration enumDeclaration = (ResolvedEnumDeclaration)typeOfScope.asReferenceType().getTypeDeclaration();
81                     if (enumDeclaration.hasEnumConstant(name)) {
82                         return Optional.of(new Value(enumDeclaration.getEnumConstant(name).getType(), name));
83                     }
84                 }
85                 Optional<ResolvedType> typeUsage = typeOfScope.asReferenceType().getFieldType(name);
86                 return typeUsage.map(resolvedType -> new Value(resolvedType, name));
87             } else {
88                 return Optional.empty();
89             }
90         } else {
91             return getParent().solveSymbolAsValue(name);
92         }
93     }
94 
solveField(String name)95     public SymbolReference<ResolvedValueDeclaration> solveField(String name) {
96         Collection<ResolvedReferenceTypeDeclaration> rrtds = findTypeDeclarations(Optional.of(wrappedNode.getScope()));
97         for (ResolvedReferenceTypeDeclaration rrtd : rrtds) {
98             if (rrtd.isEnum()) {
99                 Optional<ResolvedEnumConstantDeclaration> enumConstant = rrtd.asEnum().getEnumConstants().stream().filter(c -> c.getName().equals(name)).findFirst();
100                 if (enumConstant.isPresent()) {
101                     return SymbolReference.solved(enumConstant.get());
102                 }
103             }
104             try {
105                 return SymbolReference.solved(rrtd.getField(wrappedNode.getName().getId()));
106             } catch (Throwable t) {
107             }
108         }
109         return SymbolReference.unsolved(ResolvedFieldDeclaration.class);
110     }
111 }
112