Skip to main content
summaryrefslogblamecommitdiffstats
blob: e20ccb8291ad7efb8c737dbaa18389ede7f7521d (plain) (tree)
1
2
3
4
5
6
7
8
9
                                                                                
                                                                


                                                                       
                                                           


                                         

                
                                                     
                               
                                                                                 








                                                     
                                               
                                                 
                                               




                                                               
                                             
                                                          
                                                        

                                             
                                                          
                                                                               
                                                      
                                                      
                                                           

                                                               
                                                           
                                                
                                                

                                                     
                                                                           






                                                                            







                                                                                                                          

                                               
                 
 
                         


                                                    
 
                         


                                                                                   
 
                         




                                                    


                                                       
                                                                                   

                                                                       
                                                                    

                                                                        
                                       
                                                             

                 
                         



                                                
                         



                                                                             

                           
                                                     

                                                 
 
                         
                                                                            

                                                                
 
                         
                                                                                                               

                                                                                     
 

                           
                                                                                                     

                                                                               
 



                                                                                                   





                                                                                             
                 
 
                         
                                                               
                                                           


                                                                           
                                              

                 
                         
                                             


                                                     
                         

                                                                                  


                                                             
                                                    
                                                       
                                                                      
                                                                                      
                                                                                                 

                                                                                                         
                         

                 
                         

                                                                  

                                                                                                         
 
                         

                                                                        
                                                                                                                     
 


                                                      
                         



                                                                                                     
 


                                     
                         
                                                                           
                                                                                               
                                                                                

                                                                                              
                                                                                                         
                                                                 
                                                                                                             


                                      




                                                 









                                                                                 

                                         

                 
                         
                                                    
                                                                             
                                            
                                                      



                                     
                         



                                                                                   
                         


                                                    




                                                     
         
 














                                                                                                                      
                                                                                     
                                                                   

                                                                                                      




                                                                               
                                                                                                                                




                                                    
 


                                                                                                  
                                                
                                                    

                                                                                                                                          
 
                                                         
                         









                                                                                                        
                                                                           
                                     

                                                                                               
                                                           
                                                                          


















                                                                                        
                                                                                        









                                                                                  
                                                                 
                                                                                                 
                                                
                 
                                                        

                                                       
                                                            
                 
                                          
                                                                                   
                                        
                                                         
                                                
                                                                               
                         
                                                  







                                                                  
                                                            
                                              

                                                          
                                                                 
                                             
                                                                                  
                                                     
                                                                                                







                                                                 
                                                                     
                     

                                                                                      
                                             
                                                                                                      



                                                                       
                                                                                
                                    
                 
         
 

                                                                                                             
                                                                                                                     
                                                               
                                                                                      



                             
 
                                                           
                                                           

                                                                                       
                                                                                                     
                                                                                     
                                                                                            
                                                                                                                                   





                                                                              
 
                                       
                                                        

                                                  
                                                                         



                                                     
                                                                   









                                                                                       




                                                                                                 
 






                                                                                                                  
 
/*******************************************************************************
 * Copyright (c) 2008, 2015 Wind River Systems, Inc. and others.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     Markus Schorn - initial API and implementation
 *     Sergey Prigogin (Google)
 *******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.eclipse.cdt.core.dom.IName;
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
import org.eclipse.cdt.core.dom.ast.DOMException;
import org.eclipse.cdt.core.dom.ast.EScopeKind;
import org.eclipse.cdt.core.dom.ast.IASTASMDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTCompositeTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.IScope;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassTemplate;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassTemplatePartialSpecialization;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespace;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespaceScope;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateDefinition;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateInstance;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPUsingDirective;
import org.eclipse.cdt.core.index.IIndexBinding;
import org.eclipse.cdt.core.index.IIndexFileSet;
import org.eclipse.cdt.core.parser.util.ArrayUtil;
import org.eclipse.cdt.core.parser.util.CharArrayMap;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPTemplates;
import org.eclipse.cdt.internal.core.index.IIndexScope;

/**
 * Utility to map index-scopes to scopes from the AST. This is important for
 * scopes that can be reopened, i.e. namespaces.
 */
public class CPPScopeMapper {
	/**
	 * Used for implicit inline directives for inline namespaces found in the index.
	 */
	public static final class InlineNamespaceDirective implements ICPPUsingDirective {
		private final ICPPInternalNamespaceScope fContainer;
		private final ICPPInternalNamespaceScope fNominated;

		public InlineNamespaceDirective(ICPPInternalNamespaceScope container, ICPPInternalNamespaceScope inline) {
			fContainer = container;
			fNominated = inline;
		}

		@Override
		public IScope getContainingScope() {
			return fContainer;
		}

		@Override
		public ICPPNamespaceScope getNominatedScope() throws DOMException {
			return fNominated;
		}

		@Override
		public int getPointOfDeclaration() {
			return 0;
		}
	}

	/**
	 * Wrapper for namespace-scopes from the index.
	 */
	private class NamespaceScopeWrapper implements ICPPInternalNamespaceScope {
		private final ICPPNamespaceScope fScope;
		private ArrayList<ICPPUsingDirective> fUsingDirectives;
		private ICPPNamespaceScope[] fEnclosingNamespaceSet;

		public NamespaceScopeWrapper(ICPPNamespaceScope scope) {
			fScope = scope;
			assert fScope instanceof IIndexScope;
		}

		@Override
		public EScopeKind getKind() {
			return fScope.getKind();
		}

		@Override
		public IBinding[] find(String name, IASTTranslationUnit tu) {
			return fScope.find(name, tu);
		}

		@Override
		@Deprecated
		public IBinding[] find(String name) {
			return fScope.find(name);
		}

		@Override
		public IBinding getBinding(IASTName name, boolean resolve) {
			return fScope.getBinding(name, resolve);
		}

		@Override
		public IBinding getBinding(IASTName name, boolean resolve, IIndexFileSet acceptLocalBindings) {
			return fScope.getBinding(name, resolve, acceptLocalBindings);
		}

		@Override
		@Deprecated
		public IBinding[] getBindings(IASTName name, boolean resolve, boolean prefixLookup) {
			return fScope.getBindings(name, resolve, prefixLookup);
		}

		@Override
		@Deprecated
		public IBinding[] getBindings(IASTName name, boolean resolve, boolean prefixLookup,
				IIndexFileSet acceptLocalBindings) {
			return getBindings(name, resolve, prefixLookup, acceptLocalBindings);
		}

		@Override
		public IBinding[] getBindings(ScopeLookupData lookup) {
			return fScope.getBindings(lookup);
		}

		@Override
		public IScope getParent() throws DOMException {
			IScope parent = fScope.getParent();
			if (parent instanceof IIndexScope) {
				return mapToASTScope((IIndexScope) parent);
			}
			return fTu.getScope();
		}

		@Override
		public IName getScopeName() {
			return fScope.getScopeName();
		}

		@Override
		public void addUsingDirective(ICPPUsingDirective usingDirective) {
			initUsingDirectives();
			fUsingDirectives.add(usingDirective);
		}

		private void initUsingDirectives() {
			if (fUsingDirectives == null) {
				fUsingDirectives = new ArrayList<>(1);
				// Insert a using directive for every inline namespace
				for (ICPPInternalNamespaceScope inline : getInlineNamespaces()) {
					fUsingDirectives.add(new InlineNamespaceDirective(this, inline));
				}
			}
		}

		@Override
		public ICPPUsingDirective[] getUsingDirectives() {
			initUsingDirectives();
			return fUsingDirectives.toArray(new ICPPUsingDirective[fUsingDirectives.size()]);
		}

		@Override
		public ICPPNamespaceScope[] getEnclosingNamespaceSet() {
			if (fEnclosingNamespaceSet == null)
				return fEnclosingNamespaceSet = CPPNamespaceScope.computeEnclosingNamespaceSet(this);

			return fEnclosingNamespaceSet;
		}

		@Override
		public boolean isInlineNamepace() {
			IIndexBinding binding = ((IIndexScope) fScope).getScopeBinding();
			if (binding instanceof ICPPNamespace && ((ICPPNamespace) binding).isInline())
				return true;

			return false;
		}

		@Override
		public ICPPInternalNamespaceScope[] getInlineNamespaces() {
			// Obtain the inline namespaces from the index and map them to the AST.
			ICPPNamespaceScope[] pre = fScope.getInlineNamespaces();
			if (pre.length == 0)
				return ICPPInternalNamespaceScope.EMPTY_NAMESPACE_SCOPE_ARRAY;
			ICPPInternalNamespaceScope[] result = new ICPPInternalNamespaceScope[pre.length];
			for (int i = 0; i < result.length; i++) {
				result[i] = (ICPPInternalNamespaceScope) mapToASTScope((IIndexScope) pre[i]);
			}
			return result;
		}

		@Override
		public String toString() {
			return fScope.toString();
		}
	}

	/**
	 * Wrapper for using directives from the index.
	 */
	private class UsingDirectiveWrapper implements ICPPUsingDirective {
		private final int fOffset;
		private final ICPPUsingDirective fDirective;

		public UsingDirectiveWrapper(int offset, ICPPUsingDirective ud) {
			fOffset = offset;
			fDirective = ud;
		}

		@Override
		public IScope getContainingScope() {
			final IScope scope = fDirective.getContainingScope();
			if (scope == null) {
				return fTu.getScope();
			}
			return scope;
		}

		@Override
		public ICPPNamespaceScope getNominatedScope() throws DOMException {
			return fDirective.getNominatedScope();
		}

		@Override
		public int getPointOfDeclaration() {
			return fOffset;
		}

		@Override
		public String toString() {
			return fDirective.toString();
		}
	}

	/**
	 * Collector for class definitions.
	 */
	private class Visitor extends ASTVisitor {
		Visitor() {
			shouldVisitDeclarations = true;
		}

		@Override
		public int visit(IASTDeclaration declaration) {
			if (declaration instanceof IASTSimpleDeclaration) {
				IASTDeclSpecifier declspec = ((IASTSimpleDeclaration) declaration).getDeclSpecifier();
				if (declspec instanceof IASTCompositeTypeSpecifier) {
					IASTCompositeTypeSpecifier cts = (IASTCompositeTypeSpecifier) declspec;
					final IASTName name = cts.getName();
					final char[] nameChars = name.getLookupKey();
					if (nameChars.length > 0) {
						IASTName[] names = fClasses.get(nameChars);
						names = ArrayUtil.append(IASTName.class, names, name);
						fClasses.put(nameChars, names);
					}
					return PROCESS_CONTINUE;
				}
				return PROCESS_SKIP;
			} else if (declaration instanceof IASTASMDeclaration || declaration instanceof IASTFunctionDefinition) {
				return PROCESS_SKIP;
			}
			return PROCESS_CONTINUE;
		}
	}

	private final HashMap<IIndexScope, IScope> fMappedScopes = new HashMap<>();
	private final HashMap<String, NamespaceScopeWrapper> fNamespaceWrappers = new HashMap<>();
	private final Map<String, List<UsingDirectiveWrapper>> fPerName = new HashMap<>();
	private final CPPASTTranslationUnit fTu;
	protected CharArrayMap<IASTName[]> fClasses;

	private final Map<ICPPClassTemplatePartialSpecialization, ICPPClassTemplatePartialSpecialization> fPartialSpecs = new HashMap<>();

	public CPPScopeMapper(CPPASTTranslationUnit tu) {
		fTu = tu;
	}

	/**
	 * Register an additional list of using directives to be considered.
	 * @param offset the global offset at which the using directives are provided
	 * @param usingDirectives the list of additional directives.
	 */
	public void registerAdditionalDirectives(int offset, List<ICPPUsingDirective> usingDirectives) {
		if (!usingDirectives.isEmpty()) {
			for (ICPPUsingDirective ud : usingDirectives) {
				IScope container = ud.getContainingScope();
				try {
					final String name = getReverseQualifiedName(container);
					List<UsingDirectiveWrapper> list = fPerName.get(name);
					if (list == null) {
						list = new LinkedList<>();
						fPerName.put(name, list);
					}
					list.add(new UsingDirectiveWrapper(offset, ud));
				} catch (DOMException e) {
				}
			}
		}
	}

	/**
	 * Adds additional directives previously registered to the given scope.
	 */
	public void handleAdditionalDirectives(ICPPNamespaceScope scope) {
		assert !(scope instanceof IIndexScope);
		if (fPerName.isEmpty()) {
			return;
		}
		try {
			String qname = getReverseQualifiedName(scope);
			List<UsingDirectiveWrapper> candidates = fPerName.remove(qname);
			if (candidates != null) {
				for (UsingDirectiveWrapper ud : candidates) {
					scope.addUsingDirective(ud);
				}
			}
		} catch (DOMException e) {
		}
	}

	private String getReverseQualifiedName(IScope scope) throws DOMException {
		final CPPNamespaceScope tuscope = fTu.getScope();
		if (scope == tuscope || scope == null || scope.getKind() == EScopeKind.eGlobal) {
			return ""; //$NON-NLS-1$
		}
		StringBuilder buf = new StringBuilder();
		IName scopeName = scope.getScopeName();
		if (scopeName != null) {
			buf.append(scopeName.getSimpleID());
		}
		scope = scope.getParent();
		while (scope.getKind() != EScopeKind.eGlobal && scope != tuscope) {
			buf.append(':');
			scopeName = scope.getScopeName();
			if (scopeName != null) {
				buf.append(scope.getScopeName().getSimpleID());
			}
			scope = scope.getParent();
		}
		return buf.toString();
	}

	/**
	 * Maps namespace scopes from the index back into the AST.
	 */
	public IScope mapToASTScope(IIndexScope scope) {
		if (scope.getKind() == EScopeKind.eGlobal) {
			return fTu.getScope();
		}
		if (scope instanceof ICPPNamespaceScope) {
			IScope result = fMappedScopes.get(scope);
			if (result == null) {
				result = fTu.getScope().findNamespaceScope(scope);
				if (result == null) {
					result = wrapNamespaceScope((ICPPNamespaceScope) scope);
				}
				fMappedScopes.put(scope, result);
			}
			return result;
		}
		return scope;
	}

	private IScope wrapNamespaceScope(ICPPNamespaceScope scope) {
		try {
			String rqname = getReverseQualifiedName(scope);
			NamespaceScopeWrapper result = fNamespaceWrappers.get(rqname);
			if (result == null) {
				result = new NamespaceScopeWrapper(getCompositeNamespaceScope(scope));
				fNamespaceWrappers.put(rqname, result);
			}
			return result;
		} catch (DOMException e) {
			assert false; // index scopes don't throw dom-exceptions
			return null;
		}
	}

	private ICPPNamespaceScope getCompositeNamespaceScope(ICPPNamespaceScope scope) throws DOMException {
		if (scope instanceof IIndexScope) {
			IIndexBinding binding = fTu.getIndex().adaptBinding(((IIndexScope) scope).getScopeBinding());
			if (binding instanceof ICPPNamespace) {
				scope = ((ICPPNamespace) binding).getNamespaceScope();
			}
		}
		return scope;
	}

	public ICPPClassType mapToAST(ICPPClassType type) {
		if (type instanceof ICPPTemplateInstance) {
			ICPPTemplateInstance inst = (ICPPTemplateInstance) type;
			ICPPTemplateDefinition template = inst.getTemplateDefinition();
			if (template instanceof IIndexBinding && template instanceof ICPPClassType) {
				IBinding mapped = mapToAST((ICPPClassType) template);
				if (mapped != template && mapped instanceof ICPPClassType) {
					mapped = CPPTemplates.instantiate((ICPPClassTemplate) mapped, inst.getTemplateArguments());
					if (mapped instanceof ICPPClassType)
						return (ICPPClassType) mapped;
				}
			}
			return type;
		}

		if (fClasses == null) {
			fClasses = new CharArrayMap<>();
			fTu.accept(new Visitor());
		}
		IASTName[] names = fClasses.get(type.getNameCharArray());
		if (names != null) {
			for (IASTName name : names) {
				if (name == null)
					break;
				IBinding b = name.resolveBinding();
				if (b instanceof ICPPClassType) {
					final ICPPClassType mapped = (ICPPClassType) b;
					if (mapped.isSameType(type)) {
						return mapped;
					}
				}
			}
		}
		return type;
	}

	public void recordPartialSpecialization(ICPPClassTemplatePartialSpecialization indexSpec,
			ICPPClassTemplatePartialSpecialization astSpec) {
		fPartialSpecs.put(indexSpec, astSpec);
	}

	public ICPPClassTemplatePartialSpecialization mapToAST(ICPPClassTemplatePartialSpecialization indexSpec) {
		ICPPClassTemplatePartialSpecialization astSpec = fPartialSpecs.get(indexSpec);
		if (astSpec != null) {
			return astSpec;
		}
		return indexSpec;
	}
}

Back to the top