1683012de2a3a28358e848f8b145d462eb8b322baFederico Tomassetti/*
2683012de2a3a28358e848f8b145d462eb8b322baFederico Tomassetti * Copyright 2016 Federico Tomassetti
3683012de2a3a28358e848f8b145d462eb8b322baFederico Tomassetti *
4683012de2a3a28358e848f8b145d462eb8b322baFederico Tomassetti * Licensed under the Apache License, Version 2.0 (the "License");
5683012de2a3a28358e848f8b145d462eb8b322baFederico Tomassetti * you may not use this file except in compliance with the License.
6683012de2a3a28358e848f8b145d462eb8b322baFederico Tomassetti * You may obtain a copy of the License at
7683012de2a3a28358e848f8b145d462eb8b322baFederico Tomassetti *
8683012de2a3a28358e848f8b145d462eb8b322baFederico Tomassetti * http://www.apache.org/licenses/LICENSE-2.0
9683012de2a3a28358e848f8b145d462eb8b322baFederico Tomassetti *
10683012de2a3a28358e848f8b145d462eb8b322baFederico Tomassetti * Unless required by applicable law or agreed to in writing, software
11683012de2a3a28358e848f8b145d462eb8b322baFederico Tomassetti * distributed under the License is distributed on an "AS IS" BASIS,
12683012de2a3a28358e848f8b145d462eb8b322baFederico Tomassetti * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13683012de2a3a28358e848f8b145d462eb8b322baFederico Tomassetti * See the License for the specific language governing permissions and
14683012de2a3a28358e848f8b145d462eb8b322baFederico Tomassetti * limitations under the License.
15683012de2a3a28358e848f8b145d462eb8b322baFederico Tomassetti */
16683012de2a3a28358e848f8b145d462eb8b322baFederico Tomassetti
179c53c2cbc607ea694438ade8630be0c155a33162Federico Tomassettipackage com.github.javaparser.symbolsolver.javaparsermodel.contexts;
18d787c16867577551b1711d01f382a26af1d7a322Federico Tomassetti
19d787c16867577551b1711d01f382a26af1d7a322Federico Tomassettiimport com.github.javaparser.ast.Node;
20c08a0391fd27b2ecc75a264cce9eb4606d0f7b30Federico Tomassettiimport com.github.javaparser.ast.expr.Expression;
21c990d23490f5c4ac4322119b03d5951b63eef055Fred Lefévère-Laoideimport com.github.javaparser.ast.expr.FieldAccessExpr;
22c08a0391fd27b2ecc75a264cce9eb4606d0f7b30Federico Tomassettiimport com.github.javaparser.ast.expr.MethodCallExpr;
231db4cd7914d4f36224a4a8944e546650d5fc5a4dMarcos César de Oliveiraimport com.github.javaparser.ast.expr.NameExpr;
24223fc7650a7a3b89b43d81160f40326aaeaa98f1Federico Tomassettiimport com.github.javaparser.resolution.declarations.ResolvedValueDeclaration;
251db4cd7914d4f36224a4a8944e546650d5fc5a4dMarcos César de Oliveiraimport com.github.javaparser.resolution.declarations.ResolvedReferenceTypeDeclaration;
261db4cd7914d4f36224a4a8944e546650d5fc5a4dMarcos César de Oliveiraimport com.github.javaparser.resolution.declarations.ResolvedTypeDeclaration;
271db4cd7914d4f36224a4a8944e546650d5fc5a4dMarcos César de Oliveiraimport com.github.javaparser.resolution.declarations.ResolvedTypeParameterDeclaration;
28223fc7650a7a3b89b43d81160f40326aaeaa98f1Federico Tomassettiimport com.github.javaparser.resolution.types.ResolvedType;
291e7780e554428a10c73de88ca64e5933b2291593Federico Tomassettiimport com.github.javaparser.symbolsolver.core.resolution.Context;
301db4cd7914d4f36224a4a8944e546650d5fc5a4dMarcos César de Oliveiraimport com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade;
319c53c2cbc607ea694438ade8630be0c155a33162Federico Tomassettiimport com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFactory;
329c53c2cbc607ea694438ade8630be0c155a33162Federico Tomassettiimport com.github.javaparser.symbolsolver.model.resolution.SymbolReference;
339c53c2cbc607ea694438ade8630be0c155a33162Federico Tomassettiimport com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
349c53c2cbc607ea694438ade8630be0c155a33162Federico Tomassettiimport com.github.javaparser.symbolsolver.model.resolution.Value;
351db4cd7914d4f36224a4a8944e546650d5fc5a4dMarcos César de Oliveiraimport com.github.javaparser.symbolsolver.reflectionmodel.ReflectionClassDeclaration;
361e7780e554428a10c73de88ca64e5933b2291593Federico Tomassettiimport com.github.javaparser.symbolsolver.resolution.SymbolDeclarator;
37d787c16867577551b1711d01f382a26af1d7a322Federico Tomassetti
38b54617e765d73b3ce0d187cf12ad8da382bce439Danny van Bruggenimport java.util.*;
392568d9ebe91ceb0a13c98b16f99593cd22084efaFederico Tomassetti
4099c0277ff34b0d97af1019ac91f20a19db364410Federico Tomassettiimport static com.github.javaparser.symbolsolver.javaparser.Navigator.getParentNode;
41b54617e765d73b3ce0d187cf12ad8da382bce439Danny van Bruggenimport static com.github.javaparser.symbolsolver.javaparser.Navigator.requireParentNode;
42b54617e765d73b3ce0d187cf12ad8da382bce439Danny van Bruggenimport static java.util.Collections.*;
433e4b012ca278ee33e9e02984367028cb1adf4bf5Federico Tomassetti
44d787c16867577551b1711d01f382a26af1d7a322Federico Tomassetti/**
45e7704aa00835e056f7870bcb255db697f1f7ca25Federico Tomassetti * @author Federico Tomassetti
46d787c16867577551b1711d01f382a26af1d7a322Federico Tomassetti */
47d787c16867577551b1711d01f382a26af1d7a322Federico Tomassettipublic abstract class AbstractJavaParserContext<N extends Node> implements Context {
48d787c16867577551b1711d01f382a26af1d7a322Federico Tomassetti
49d787c16867577551b1711d01f382a26af1d7a322Federico Tomassetti    protected N wrappedNode;
500e81f51c40996b42cb262dc2397126cee8f60965Federico Tomassetti    protected TypeSolver typeSolver;
51d787c16867577551b1711d01f382a26af1d7a322Federico Tomassetti
526df1aa26f75ff0d716a1290007e2b63cc05001aeFederico Tomassetti    ///
536df1aa26f75ff0d716a1290007e2b63cc05001aeFederico Tomassetti    /// Static methods
546df1aa26f75ff0d716a1290007e2b63cc05001aeFederico Tomassetti    ///
5549719b4acbe10e3714ceb4f7040acac34709f558Federico Tomassetti
56b54617e765d73b3ce0d187cf12ad8da382bce439Danny van Bruggen    public static SymbolReference<ResolvedValueDeclaration> solveWith(SymbolDeclarator symbolDeclarator, String name) {
57223fc7650a7a3b89b43d81160f40326aaeaa98f1Federico Tomassetti        for (ResolvedValueDeclaration decl : symbolDeclarator.getSymbolDeclarations()) {
5849719b4acbe10e3714ceb4f7040acac34709f558Federico Tomassetti            if (decl.getName().equals(name)) {
5949719b4acbe10e3714ceb4f7040acac34709f558Federico Tomassetti                return SymbolReference.solved(decl);
6049719b4acbe10e3714ceb4f7040acac34709f558Federico Tomassetti            }
6149719b4acbe10e3714ceb4f7040acac34709f558Federico Tomassetti        }
62223fc7650a7a3b89b43d81160f40326aaeaa98f1Federico Tomassetti        return SymbolReference.unsolved(ResolvedValueDeclaration.class);
6349719b4acbe10e3714ceb4f7040acac34709f558Federico Tomassetti    }
6449719b4acbe10e3714ceb4f7040acac34709f558Federico Tomassetti
656df1aa26f75ff0d716a1290007e2b63cc05001aeFederico Tomassetti    ///
666df1aa26f75ff0d716a1290007e2b63cc05001aeFederico Tomassetti    /// Constructors
676df1aa26f75ff0d716a1290007e2b63cc05001aeFederico Tomassetti    ///
686df1aa26f75ff0d716a1290007e2b63cc05001aeFederico Tomassetti
696df1aa26f75ff0d716a1290007e2b63cc05001aeFederico Tomassetti    public AbstractJavaParserContext(N wrappedNode, TypeSolver typeSolver) {
706df1aa26f75ff0d716a1290007e2b63cc05001aeFederico Tomassetti        if (wrappedNode == null) {
716df1aa26f75ff0d716a1290007e2b63cc05001aeFederico Tomassetti            throw new NullPointerException();
726df1aa26f75ff0d716a1290007e2b63cc05001aeFederico Tomassetti        }
736df1aa26f75ff0d716a1290007e2b63cc05001aeFederico Tomassetti        this.wrappedNode = wrappedNode;
746df1aa26f75ff0d716a1290007e2b63cc05001aeFederico Tomassetti        this.typeSolver = typeSolver;
756df1aa26f75ff0d716a1290007e2b63cc05001aeFederico Tomassetti    }
766df1aa26f75ff0d716a1290007e2b63cc05001aeFederico Tomassetti
776df1aa26f75ff0d716a1290007e2b63cc05001aeFederico Tomassetti    ///
786df1aa26f75ff0d716a1290007e2b63cc05001aeFederico Tomassetti    /// Public methods
796df1aa26f75ff0d716a1290007e2b63cc05001aeFederico Tomassetti    ///
806df1aa26f75ff0d716a1290007e2b63cc05001aeFederico Tomassetti
81bb4473f790e2da86cdce011f7f867a51883aab48Federico Tomassetti    @Override
82bb4473f790e2da86cdce011f7f867a51883aab48Federico Tomassetti    public boolean equals(Object o) {
83bb4473f790e2da86cdce011f7f867a51883aab48Federico Tomassetti        if (this == o) return true;
84bb4473f790e2da86cdce011f7f867a51883aab48Federico Tomassetti        if (o == null || getClass() != o.getClass()) return false;
85bb4473f790e2da86cdce011f7f867a51883aab48Federico Tomassetti
86c990d23490f5c4ac4322119b03d5951b63eef055Fred Lefévère-Laoide        AbstractJavaParserContext<?> that = (AbstractJavaParserContext<?>) o;
87bb4473f790e2da86cdce011f7f867a51883aab48Federico Tomassetti
88bb4473f790e2da86cdce011f7f867a51883aab48Federico Tomassetti        if (wrappedNode != null ? !wrappedNode.equals(that.wrappedNode) : that.wrappedNode != null) return false;
89bb4473f790e2da86cdce011f7f867a51883aab48Federico Tomassetti
90bb4473f790e2da86cdce011f7f867a51883aab48Federico Tomassetti        return true;
91bb4473f790e2da86cdce011f7f867a51883aab48Federico Tomassetti    }
92bb4473f790e2da86cdce011f7f867a51883aab48Federico Tomassetti
93bb4473f790e2da86cdce011f7f867a51883aab48Federico Tomassetti    @Override
94bb4473f790e2da86cdce011f7f867a51883aab48Federico Tomassetti    public int hashCode() {
95bb4473f790e2da86cdce011f7f867a51883aab48Federico Tomassetti        return wrappedNode != null ? wrappedNode.hashCode() : 0;
96bb4473f790e2da86cdce011f7f867a51883aab48Federico Tomassetti    }
97bb4473f790e2da86cdce011f7f867a51883aab48Federico Tomassetti
98535dd7001046e740345e2d00cb27f13d69226521Federico Tomassetti    @Override
99223fc7650a7a3b89b43d81160f40326aaeaa98f1Federico Tomassetti    public Optional<ResolvedType> solveGenericType(String name, TypeSolver typeSolver) {
100535dd7001046e740345e2d00cb27f13d69226521Federico Tomassetti        Context parent = getParent();
101535dd7001046e740345e2d00cb27f13d69226521Federico Tomassetti        if (parent == null) {
102535dd7001046e740345e2d00cb27f13d69226521Federico Tomassetti            return Optional.empty();
103535dd7001046e740345e2d00cb27f13d69226521Federico Tomassetti        } else {
104535dd7001046e740345e2d00cb27f13d69226521Federico Tomassetti            return parent.solveGenericType(name, typeSolver);
105535dd7001046e740345e2d00cb27f13d69226521Federico Tomassetti        }
106535dd7001046e740345e2d00cb27f13d69226521Federico Tomassetti    }
107535dd7001046e740345e2d00cb27f13d69226521Federico Tomassetti
108d787c16867577551b1711d01f382a26af1d7a322Federico Tomassetti    @Override
109d787c16867577551b1711d01f382a26af1d7a322Federico Tomassetti    public final Context getParent() {
110b54617e765d73b3ce0d187cf12ad8da382bce439Danny van Bruggen        Node parent = wrappedNode.getParentNode().orElse(null);
111b54617e765d73b3ce0d187cf12ad8da382bce439Danny van Bruggen        if (parent instanceof MethodCallExpr) {
112b54617e765d73b3ce0d187cf12ad8da382bce439Danny van Bruggen            MethodCallExpr parentCall = (MethodCallExpr) parent;
113c08a0391fd27b2ecc75a264cce9eb4606d0f7b30Federico Tomassetti            boolean found = false;
11452b60cf471dc9d7b53d8f22018d9c4e4fcc15923Federico Tomassetti            if (parentCall.getArguments() != null) {
11552b60cf471dc9d7b53d8f22018d9c4e4fcc15923Federico Tomassetti                for (Expression expression : parentCall.getArguments()) {
116c08a0391fd27b2ecc75a264cce9eb4606d0f7b30Federico Tomassetti                    if (expression == wrappedNode) {
117c08a0391fd27b2ecc75a264cce9eb4606d0f7b30Federico Tomassetti                        found = true;
118c08a0391fd27b2ecc75a264cce9eb4606d0f7b30Federico Tomassetti                    }
119c08a0391fd27b2ecc75a264cce9eb4606d0f7b30Federico Tomassetti                }
120c08a0391fd27b2ecc75a264cce9eb4606d0f7b30Federico Tomassetti            }
121c08a0391fd27b2ecc75a264cce9eb4606d0f7b30Federico Tomassetti            if (found) {
122b54617e765d73b3ce0d187cf12ad8da382bce439Danny van Bruggen                Node notMethod = parent;
12345175889553f49fd90a2860e9e6fa7869730db71Federico Tomassetti                while (notMethod instanceof MethodCallExpr) {
124b54617e765d73b3ce0d187cf12ad8da382bce439Danny van Bruggen                    notMethod = requireParentNode(notMethod);
12545175889553f49fd90a2860e9e6fa7869730db71Federico Tomassetti                }
12645175889553f49fd90a2860e9e6fa7869730db71Federico Tomassetti                return JavaParserFactory.getContext(notMethod, typeSolver);
127c08a0391fd27b2ecc75a264cce9eb4606d0f7b30Federico Tomassetti            }
128c08a0391fd27b2ecc75a264cce9eb4606d0f7b30Federico Tomassetti        }
129b54617e765d73b3ce0d187cf12ad8da382bce439Danny van Bruggen        Node notMethod = parent;
130cb5ffb7fdd56f1b768d25da330fa3b29ecb74eafFederico Tomassetti        while (notMethod instanceof MethodCallExpr || notMethod instanceof FieldAccessExpr) {
131b54617e765d73b3ce0d187cf12ad8da382bce439Danny van Bruggen            notMethod = notMethod.getParentNode().orElse(null);
13245175889553f49fd90a2860e9e6fa7869730db71Federico Tomassetti        }
133478a9ba268137913d67438b1e3c8f61e5e0976a5Federico Tomassetti        if (notMethod == null) {
134478a9ba268137913d67438b1e3c8f61e5e0976a5Federico Tomassetti            return null;
135478a9ba268137913d67438b1e3c8f61e5e0976a5Federico Tomassetti        }
13645175889553f49fd90a2860e9e6fa7869730db71Federico Tomassetti        return JavaParserFactory.getContext(notMethod, typeSolver);
137d787c16867577551b1711d01f382a26af1d7a322Federico Tomassetti    }
138d787c16867577551b1711d01f382a26af1d7a322Federico Tomassetti
1396df1aa26f75ff0d716a1290007e2b63cc05001aeFederico Tomassetti    ///
1406df1aa26f75ff0d716a1290007e2b63cc05001aeFederico Tomassetti    /// Protected methods
1416df1aa26f75ff0d716a1290007e2b63cc05001aeFederico Tomassetti    ///
1426df1aa26f75ff0d716a1290007e2b63cc05001aeFederico Tomassetti
1436df1aa26f75ff0d716a1290007e2b63cc05001aeFederico Tomassetti    protected Optional<Value> solveWithAsValue(SymbolDeclarator symbolDeclarator, String name, TypeSolver typeSolver) {
1446df1aa26f75ff0d716a1290007e2b63cc05001aeFederico Tomassetti        return symbolDeclarator.getSymbolDeclarations().stream()
1456df1aa26f75ff0d716a1290007e2b63cc05001aeFederico Tomassetti                .filter(d -> d.getName().equals(name))
146b54617e765d73b3ce0d187cf12ad8da382bce439Danny van Bruggen                .map(Value::from)
1476df1aa26f75ff0d716a1290007e2b63cc05001aeFederico Tomassetti                .findFirst();
1486df1aa26f75ff0d716a1290007e2b63cc05001aeFederico Tomassetti    }
1496df1aa26f75ff0d716a1290007e2b63cc05001aeFederico Tomassetti
1501db4cd7914d4f36224a4a8944e546650d5fc5a4dMarcos César de Oliveira    protected Collection<ResolvedReferenceTypeDeclaration> findTypeDeclarations(Optional<Expression> optScope, TypeSolver typeSolver) {
1511db4cd7914d4f36224a4a8944e546650d5fc5a4dMarcos César de Oliveira        if (optScope.isPresent()) {
1521db4cd7914d4f36224a4a8944e546650d5fc5a4dMarcos César de Oliveira            Expression scope = optScope.get();
1531db4cd7914d4f36224a4a8944e546650d5fc5a4dMarcos César de Oliveira
1541db4cd7914d4f36224a4a8944e546650d5fc5a4dMarcos César de Oliveira            // consider static methods
1551db4cd7914d4f36224a4a8944e546650d5fc5a4dMarcos César de Oliveira            if (scope instanceof NameExpr) {
1561db4cd7914d4f36224a4a8944e546650d5fc5a4dMarcos César de Oliveira                NameExpr scopeAsName = (NameExpr) scope;
1571db4cd7914d4f36224a4a8944e546650d5fc5a4dMarcos César de Oliveira                SymbolReference<ResolvedTypeDeclaration> symbolReference = this.solveType(scopeAsName.getName().getId(), typeSolver);
1581db4cd7914d4f36224a4a8944e546650d5fc5a4dMarcos César de Oliveira                if (symbolReference.isSolved() && symbolReference.getCorrespondingDeclaration().isType()) {
159b54617e765d73b3ce0d187cf12ad8da382bce439Danny van Bruggen                    return singletonList(symbolReference.getCorrespondingDeclaration().asReferenceType());
1601db4cd7914d4f36224a4a8944e546650d5fc5a4dMarcos César de Oliveira                }
1611db4cd7914d4f36224a4a8944e546650d5fc5a4dMarcos César de Oliveira            }
1621db4cd7914d4f36224a4a8944e546650d5fc5a4dMarcos César de Oliveira
163b54617e765d73b3ce0d187cf12ad8da382bce439Danny van Bruggen            ResolvedType typeOfScope;
1641db4cd7914d4f36224a4a8944e546650d5fc5a4dMarcos César de Oliveira            try {
1651db4cd7914d4f36224a4a8944e546650d5fc5a4dMarcos César de Oliveira                typeOfScope = JavaParserFacade.get(typeSolver).getType(scope);
1661db4cd7914d4f36224a4a8944e546650d5fc5a4dMarcos César de Oliveira            } catch (Exception e) {
167b54617e765d73b3ce0d187cf12ad8da382bce439Danny van Bruggen                throw new RuntimeException("Issue calculating the type of the scope of " + this, e);
1681db4cd7914d4f36224a4a8944e546650d5fc5a4dMarcos César de Oliveira            }
1691db4cd7914d4f36224a4a8944e546650d5fc5a4dMarcos César de Oliveira            if (typeOfScope.isWildcard()) {
1701db4cd7914d4f36224a4a8944e546650d5fc5a4dMarcos César de Oliveira                if (typeOfScope.asWildcard().isExtends() || typeOfScope.asWildcard().isSuper()) {
171b54617e765d73b3ce0d187cf12ad8da382bce439Danny van Bruggen                    return singletonList(typeOfScope.asWildcard().getBoundedType().asReferenceType().getTypeDeclaration());
1721db4cd7914d4f36224a4a8944e546650d5fc5a4dMarcos César de Oliveira                } else {
173b54617e765d73b3ce0d187cf12ad8da382bce439Danny van Bruggen                    return singletonList(new ReflectionClassDeclaration(Object.class, typeSolver).asReferenceType());
1741db4cd7914d4f36224a4a8944e546650d5fc5a4dMarcos César de Oliveira                }
1751db4cd7914d4f36224a4a8944e546650d5fc5a4dMarcos César de Oliveira            } else if (typeOfScope.isArray()) {
1761db4cd7914d4f36224a4a8944e546650d5fc5a4dMarcos César de Oliveira                // method call on array are Object methods
177b54617e765d73b3ce0d187cf12ad8da382bce439Danny van Bruggen                return singletonList(new ReflectionClassDeclaration(Object.class, typeSolver).asReferenceType());
1781db4cd7914d4f36224a4a8944e546650d5fc5a4dMarcos César de Oliveira            } else if (typeOfScope.isTypeVariable()) {
1791db4cd7914d4f36224a4a8944e546650d5fc5a4dMarcos César de Oliveira                Collection<ResolvedReferenceTypeDeclaration> result = new ArrayList<>();
1801db4cd7914d4f36224a4a8944e546650d5fc5a4dMarcos César de Oliveira                for (ResolvedTypeParameterDeclaration.Bound bound : typeOfScope.asTypeParameter().getBounds()) {
1811db4cd7914d4f36224a4a8944e546650d5fc5a4dMarcos César de Oliveira                    result.add(bound.getType().asReferenceType().getTypeDeclaration());
1821db4cd7914d4f36224a4a8944e546650d5fc5a4dMarcos César de Oliveira                }
1831db4cd7914d4f36224a4a8944e546650d5fc5a4dMarcos César de Oliveira                return result;
184b54617e765d73b3ce0d187cf12ad8da382bce439Danny van Bruggen            } else if (typeOfScope.isConstraint()) {
185b54617e765d73b3ce0d187cf12ad8da382bce439Danny van Bruggen                return singletonList(typeOfScope.asConstraintType().getBound().asReferenceType().getTypeDeclaration());
1861db4cd7914d4f36224a4a8944e546650d5fc5a4dMarcos César de Oliveira            }
187b54617e765d73b3ce0d187cf12ad8da382bce439Danny van Bruggen            return singletonList(typeOfScope.asReferenceType().getTypeDeclaration());
1881db4cd7914d4f36224a4a8944e546650d5fc5a4dMarcos César de Oliveira        }
189b54617e765d73b3ce0d187cf12ad8da382bce439Danny van Bruggen        ResolvedType typeOfScope = JavaParserFacade.get(typeSolver).getTypeOfThisIn(wrappedNode);
190b54617e765d73b3ce0d187cf12ad8da382bce439Danny van Bruggen        return singletonList(typeOfScope.asReferenceType().getTypeDeclaration());
1911db4cd7914d4f36224a4a8944e546650d5fc5a4dMarcos César de Oliveira    }
1921db4cd7914d4f36224a4a8944e546650d5fc5a4dMarcos César de Oliveira
193d787c16867577551b1711d01f382a26af1d7a322Federico Tomassetti}
194