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.core.resolution; 18 19 import com.github.javaparser.ast.Node; 20 import com.github.javaparser.ast.body.Parameter; 21 import com.github.javaparser.ast.body.VariableDeclarator; 22 import com.github.javaparser.resolution.MethodUsage; 23 import com.github.javaparser.resolution.declarations.*; 24 import com.github.javaparser.resolution.types.ResolvedType; 25 import com.github.javaparser.symbolsolver.javaparsermodel.contexts.AbstractJavaParserContext; 26 import com.github.javaparser.symbolsolver.model.resolution.SymbolReference; 27 import com.github.javaparser.symbolsolver.model.resolution.Value; 28 29 import java.util.Collections; 30 import java.util.List; 31 import java.util.Optional; 32 33 /** 34 * Context is very similar to scope. 35 * In the context we look for solving symbols. 36 * 37 * @author Federico Tomassetti 38 */ 39 public interface Context { 40 getParent()41 Context getParent(); 42 43 /* Type resolution */ 44 solveGenericType(String name)45 default Optional<ResolvedType> solveGenericType(String name) { 46 return Optional.empty(); 47 } 48 solveType(String name)49 default SymbolReference<ResolvedTypeDeclaration> solveType(String name) { 50 Context parent = getParent(); 51 if (parent == null) { 52 return SymbolReference.unsolved(ResolvedReferenceTypeDeclaration.class); 53 } else { 54 return parent.solveType(name); 55 } 56 } 57 58 /* Symbol resolution */ 59 solveSymbol(String name)60 default SymbolReference<? extends ResolvedValueDeclaration> solveSymbol(String name) { 61 return getParent().solveSymbol(name); 62 } 63 solveSymbolAsValue(String name)64 default Optional<Value> solveSymbolAsValue(String name) { 65 SymbolReference<? extends ResolvedValueDeclaration> ref = solveSymbol(name); 66 if (ref.isSolved()) { 67 Value value = Value.from(ref.getCorrespondingDeclaration()); 68 return Optional.of(value); 69 } else { 70 return Optional.empty(); 71 } 72 } 73 74 /** 75 * The local variables that are declared in this immediate context and made visible to a given child. 76 * This list could include values which are shadowed. 77 */ localVariablesExposedToChild(Node child)78 default List<VariableDeclarator> localVariablesExposedToChild(Node child) { 79 return Collections.emptyList(); 80 } 81 82 /** 83 * The parameters that are declared in this immediate context and made visible to a given child. 84 * This list could include values which are shadowed. 85 */ parametersExposedToChild(Node child)86 default List<Parameter> parametersExposedToChild(Node child) { 87 return Collections.emptyList(); 88 } 89 90 /** 91 * The fields that are declared and in this immediate context made visible to a given child. 92 * This list could include values which are shadowed. 93 */ fieldsExposedToChild(Node child)94 default List<ResolvedFieldDeclaration> fieldsExposedToChild(Node child) { 95 return Collections.emptyList(); 96 } 97 98 /** 99 * Aim to resolve the given name by looking for a variable matching it. 100 * 101 * To do it consider local variables that are visible in a certain scope as defined in JLS 6.3. Scope of a Declaration. 102 * 103 * 1. The scope of a local variable declaration in a block (§14.4) is the rest of the block in which the declaration 104 * appears, starting with its own initializer and including any further declarators to the right in the local 105 * variable declaration statement. 106 * 107 * 2. The scope of a local variable declared in the ForInit part of a basic for statement (§14.14.1) includes all 108 * of the following: 109 * 2.1 Its own initializer 110 * 2.2 Any further declarators to the right in the ForInit part of the for statement 111 * 2.3 The Expression and ForUpdate parts of the for statement 112 * 2.4 The contained Statement 113 * 114 * 3. The scope of a local variable declared in the FormalParameter part of an enhanced for statement (§14.14.2) is 115 * the contained Statement. 116 * 4. The scope of a parameter of an exception handler that is declared in a catch clause of a try statement 117 * (§14.20) is the entire block associated with the catch. 118 * 119 * 5. The scope of a variable declared in the ResourceSpecification of a try-with-resources statement (§14.20.3) is 120 * from the declaration rightward over the remainder of the ResourceSpecification and the entire try block 121 * associated with the try-with-resources statement. 122 */ localVariableDeclarationInScope(String name)123 default Optional<VariableDeclarator> localVariableDeclarationInScope(String name) { 124 if (getParent() == null) { 125 return Optional.empty(); 126 } 127 Optional<VariableDeclarator> localRes = getParent().localVariablesExposedToChild(((AbstractJavaParserContext)this) 128 .getWrappedNode()).stream().filter(vd -> vd.getNameAsString().equals(name)).findFirst(); 129 if (localRes.isPresent()) { 130 return localRes; 131 } 132 133 return getParent().localVariableDeclarationInScope(name); 134 } 135 parameterDeclarationInScope(String name)136 default Optional<Parameter> parameterDeclarationInScope(String name) { 137 if (getParent() == null) { 138 return Optional.empty(); 139 } 140 Optional<Parameter> localRes = getParent().parametersExposedToChild(((AbstractJavaParserContext)this) 141 .getWrappedNode()).stream().filter(vd -> vd.getNameAsString().equals(name)).findFirst(); 142 if (localRes.isPresent()) { 143 return localRes; 144 } 145 146 return getParent().parameterDeclarationInScope(name); 147 } 148 fieldDeclarationInScope(String name)149 default Optional<ResolvedFieldDeclaration> fieldDeclarationInScope(String name) { 150 if (getParent() == null) { 151 return Optional.empty(); 152 } 153 Optional<ResolvedFieldDeclaration> localRes = getParent().fieldsExposedToChild(((AbstractJavaParserContext)this) 154 .getWrappedNode()).stream().filter(vd -> vd.getName().equals(name)).findFirst(); 155 if (localRes.isPresent()) { 156 return localRes; 157 } 158 159 return getParent().fieldDeclarationInScope(name); 160 } 161 162 /* Constructor resolution */ 163 164 /** 165 * We find the method declaration which is the best match for the given name and list of typeParametersValues. 166 */ solveConstructor(List<ResolvedType> argumentsTypes)167 default SymbolReference<ResolvedConstructorDeclaration> solveConstructor(List<ResolvedType> argumentsTypes) { 168 throw new IllegalArgumentException("Constructor resolution is available only on Class Context"); 169 } 170 171 /* Methods resolution */ 172 173 /** 174 * We find the method declaration which is the best match for the given name and list of typeParametersValues. 175 */ solveMethod(String name, List<ResolvedType> argumentsTypes, boolean staticOnly)176 default SymbolReference<ResolvedMethodDeclaration> solveMethod(String name, List<ResolvedType> argumentsTypes, 177 boolean staticOnly) { 178 return getParent().solveMethod(name, argumentsTypes, staticOnly); 179 } 180 181 /** 182 * Similar to solveMethod but we return a MethodUsage. A MethodUsage corresponds to a MethodDeclaration plus the 183 * resolved type variables. 184 */ solveMethodAsUsage(String name, List<ResolvedType> argumentsTypes)185 default Optional<MethodUsage> solveMethodAsUsage(String name, List<ResolvedType> argumentsTypes) { 186 SymbolReference<ResolvedMethodDeclaration> methodSolved = solveMethod(name, argumentsTypes, false); 187 if (methodSolved.isSolved()) { 188 ResolvedMethodDeclaration methodDeclaration = methodSolved.getCorrespondingDeclaration(); 189 190 MethodUsage methodUsage; 191 if (methodDeclaration instanceof TypeVariableResolutionCapability) { 192 methodUsage = ((TypeVariableResolutionCapability) methodDeclaration) 193 .resolveTypeVariables(this, argumentsTypes); 194 } else { 195 throw new UnsupportedOperationException("Resolved method declarations should have the " + 196 TypeVariableResolutionCapability.class.getName() + "."); 197 } 198 199 return Optional.of(methodUsage); 200 } else { 201 return Optional.empty(); 202 } 203 } 204 205 } 206