mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-07-01 14:15:23 +02:00
Bug 457301 - Organize Includes ignores IWYU pragma: keep
This commit is contained in:
parent
6a7b37ca6a
commit
49997a17b3
8 changed files with 179 additions and 18 deletions
|
@ -1,5 +1,5 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2000, 2014 QNX Software Systems and others.
|
||||
* Copyright (c) 2000, 2015 QNX Software Systems and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
|
@ -234,6 +234,22 @@ public class CCorePreferenceConstants {
|
|||
*/
|
||||
public static final String INCLUDE_PRIVATE_PATTERN = "includes.privatePattern"; //$NON-NLS-1$
|
||||
|
||||
/**
|
||||
* Default value for {@link #INCLUDE_KEEP_PATTERN}.
|
||||
* @since 5.9
|
||||
*/
|
||||
public static final String DEFAULT_INCLUDE_KEEP_PATTERN = "IWYU\\s+(pragma:?\\s+)?keep"; //$NON-NLS-1$
|
||||
|
||||
/**
|
||||
* Preference key for the regular expression pattern that, when appears in a comment on the same
|
||||
* line as include statement, indicates that the include statement should be preserved when
|
||||
* organizing includes.
|
||||
* @see "https://code.google.com/p/include-what-you-use/wiki/IWYUPragmas"
|
||||
*
|
||||
* @since 5.9
|
||||
*/
|
||||
public static final String INCLUDE_KEEP_PATTERN = "includes.keepPattern"; //$NON-NLS-1$
|
||||
|
||||
/**
|
||||
* A named preference that controls whether the parser should skip trivial expressions in initializer lists.
|
||||
* <p>
|
||||
|
@ -301,17 +317,31 @@ public class CCorePreferenceConstants {
|
|||
|
||||
/**
|
||||
* Returns the node in the preference in the given context.
|
||||
*
|
||||
* @param key The preference key.
|
||||
* @param cProject The current context or {@code null} if no context is available and
|
||||
* the workspace setting should be taken. Note that passing {@code null} should
|
||||
* be avoided.
|
||||
* @return Returns the node matching the given context.
|
||||
*/
|
||||
private static IEclipsePreferences getPreferenceNode(String key, ICProject cProject) {
|
||||
IProject project = cProject == null ? null : cProject.getProject();
|
||||
return getPreferenceNode(key, project);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the node in the preference in the given context.
|
||||
*
|
||||
* @param key The preference key.
|
||||
* @param project The current context or {@code null} if no context is available and
|
||||
* the workspace setting should be taken. Note that passing {@code null} should
|
||||
* be avoided.
|
||||
* @return Returns the node matching the given context.
|
||||
*/
|
||||
private static IEclipsePreferences getPreferenceNode(String key, ICProject project) {
|
||||
private static IEclipsePreferences getPreferenceNode(String key, IProject project) {
|
||||
IEclipsePreferences node = null;
|
||||
|
||||
if (project != null) {
|
||||
node = new ProjectScope(project.getProject()).getNode(CCorePlugin.PLUGIN_ID);
|
||||
node = new ProjectScope(project).getNode(CCorePlugin.PLUGIN_ID);
|
||||
if (node.get(key, null) != null) {
|
||||
return node;
|
||||
}
|
||||
|
@ -331,6 +361,7 @@ public class CCorePreferenceConstants {
|
|||
|
||||
/**
|
||||
* Returns the string value for the given key in the given context.
|
||||
*
|
||||
* @param key The preference key
|
||||
* @param project The current context or {@code null} if no context is available and
|
||||
* the workspace setting should be taken. Note that passing {@code null} should be avoided.
|
||||
|
@ -343,6 +374,20 @@ public class CCorePreferenceConstants {
|
|||
|
||||
/**
|
||||
* Returns the string value for the given key in the given context.
|
||||
*
|
||||
* @param key The preference key
|
||||
* @param project The current context or {@code null} if no context is available and
|
||||
* the workspace setting should be taken. Note that passing {@code null} should be avoided.
|
||||
* @return Returns the current value for the string.
|
||||
* @since 5.9
|
||||
*/
|
||||
public static String getPreference(String key, IProject project) {
|
||||
return getPreference(key, project, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the string value for the given key in the given context.
|
||||
*
|
||||
* @param key The preference key
|
||||
* @param project The current context or {@code null} if no context is available and
|
||||
* the workspace setting should be taken. Note that passing {@code null} should be avoided.
|
||||
|
@ -354,8 +399,23 @@ public class CCorePreferenceConstants {
|
|||
return getPreferenceNode(key, project).get(key, defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the string value for the given key in the given context.
|
||||
*
|
||||
* @param key The preference key
|
||||
* @param project The current context or {@code null} if no context is available and
|
||||
* the workspace setting should be taken. Note that passing {@code null} should be avoided.
|
||||
* @param defaultValue The default value if not specified in the preferences.
|
||||
* @return Returns the current value of the preference.
|
||||
* @since 5.9
|
||||
*/
|
||||
public static String getPreference(String key, IProject project, String defaultValue) {
|
||||
return getPreferenceNode(key, project).get(key, defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the integer value for the given key in the given context.
|
||||
*
|
||||
* @param key The preference key
|
||||
* @param project The current context or {@code null} if no context is available and
|
||||
* the workspace setting should be taken. Note that passing {@code null} should be avoided.
|
||||
|
@ -367,8 +427,23 @@ public class CCorePreferenceConstants {
|
|||
return getPreferenceNode(key, project).getInt(key, defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the integer value for the given key in the given context.
|
||||
*
|
||||
* @param key The preference key
|
||||
* @param project The current context or {@code null} if no context is available and
|
||||
* the workspace setting should be taken. Note that passing {@code null} should be avoided.
|
||||
* @param defaultValue The default value if not specified in the preferences.
|
||||
* @return Returns the current value of the preference.
|
||||
* @since 5.9
|
||||
*/
|
||||
public static int getPreference(String key, IProject project, int defaultValue) {
|
||||
return getPreferenceNode(key, project).getInt(key, defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the boolean value for the given key in the given context.
|
||||
*
|
||||
* @param key The preference key
|
||||
* @param project The current context or {@code null} if no context is available and
|
||||
* the workspace setting should be taken. Note that passing {@code null} should be avoided.
|
||||
|
@ -380,6 +455,20 @@ public class CCorePreferenceConstants {
|
|||
return getPreferenceNode(key, project).getBoolean(key, defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the boolean value for the given key in the given context.
|
||||
*
|
||||
* @param key The preference key
|
||||
* @param project The current context or {@code null} if no context is available and
|
||||
* the workspace setting should be taken. Note that passing {@code null} should be avoided.
|
||||
* @param defaultValue The default value if not specified in the preferences.
|
||||
* @return Returns the current value of the preference.
|
||||
* @since 5.9
|
||||
*/
|
||||
public static boolean getPreference(String key, IProject project, boolean defaultValue) {
|
||||
return getPreferenceNode(key, project).getBoolean(key, defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the scopes for preference lookup.
|
||||
*
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2000, 2014 QNX Software Systems and others.
|
||||
* Copyright (c) 2000, 2015 QNX Software Systems and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
|
@ -68,6 +68,7 @@ public class CCorePreferenceInitializer extends AbstractPreferenceInitializer {
|
|||
defaultPreferences.put(CCorePreferenceConstants.INCLUDE_BEGIN_EXPORTS_PATTERN, CCorePreferenceConstants.DEFAULT_INCLUDE_BEGIN_EXPORTS_PATTERN);
|
||||
defaultPreferences.put(CCorePreferenceConstants.INCLUDE_END_EXPORTS_PATTERN, CCorePreferenceConstants.DEFAULT_INCLUDE_END_EXPORTS_PATTERN);
|
||||
defaultPreferences.put(CCorePreferenceConstants.INCLUDE_PRIVATE_PATTERN, CCorePreferenceConstants.DEFAULT_INCLUDE_PRIVATE_PATTERN);
|
||||
defaultPreferences.put(CCorePreferenceConstants.INCLUDE_KEEP_PATTERN, CCorePreferenceConstants.DEFAULT_INCLUDE_KEEP_PATTERN);
|
||||
|
||||
// Scalability defaults.
|
||||
defaultPreferences.putBoolean(CCorePreferenceConstants.SCALABILITY_SKIP_TRIVIAL_EXPRESSIONS, CCorePreferenceConstants.DEFAULT_SCALABILITY_SKIP_TRIVIAL_EXPRESSIONS);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2013, 2014 Google, Inc and others.
|
||||
* Copyright (c) 2013, 2015 Google, Inc and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
|
@ -428,6 +428,23 @@ public class IncludeOrganizerTest extends IncludesTestBase {
|
|||
assertExpectedResults();
|
||||
}
|
||||
|
||||
//h1.h
|
||||
|
||||
//h2.h
|
||||
|
||||
//h3.h
|
||||
|
||||
//source.cpp
|
||||
//#include "h1.h"
|
||||
//#include "h2.h" // IWYU pragma: keep
|
||||
//#include "h3.h" /* IWYU pragma: keep */
|
||||
//====================
|
||||
//#include "h2.h" // IWYU pragma: keep
|
||||
//#include "h3.h" /* IWYU pragma: keep */
|
||||
public void testPragmaKeep() throws Exception {
|
||||
assertExpectedResults();
|
||||
}
|
||||
|
||||
//h1.h
|
||||
//#define M2(t, p) t p
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2013, 2014 Google, Inc and others.
|
||||
* Copyright (c) 2013, 2015 Google, Inc and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
|
@ -13,12 +13,15 @@ package org.eclipse.cdt.internal.corext.codemanipulation;
|
|||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.regex.PatternSyntaxException;
|
||||
|
||||
import org.eclipse.core.resources.IFile;
|
||||
import org.eclipse.core.resources.IProject;
|
||||
import org.eclipse.core.runtime.IPath;
|
||||
import org.eclipse.core.runtime.Path;
|
||||
|
||||
import org.eclipse.cdt.core.CCorePreferenceConstants;
|
||||
import org.eclipse.cdt.core.model.CModelException;
|
||||
import org.eclipse.cdt.core.model.ICProject;
|
||||
import org.eclipse.cdt.core.model.ITranslationUnit;
|
||||
|
@ -48,6 +51,7 @@ public class InclusionContext {
|
|||
private final IncludePreferences fPreferences;
|
||||
private String fSourceContents;
|
||||
private String fLineDelimiter;
|
||||
private Pattern fKeepPragmaPattern;
|
||||
private IPath fTuLocation;
|
||||
|
||||
public InclusionContext(ITranslationUnit tu) {
|
||||
|
@ -295,6 +299,20 @@ public class InclusionContext {
|
|||
return fLineDelimiter;
|
||||
}
|
||||
|
||||
public Pattern getKeepPragmaPattern() {
|
||||
if (fKeepPragmaPattern == null) {
|
||||
String keepPattern = CCorePreferenceConstants.getPreference(
|
||||
CCorePreferenceConstants.INCLUDE_KEEP_PATTERN, fProject,
|
||||
CCorePreferenceConstants.DEFAULT_INCLUDE_KEEP_PATTERN);
|
||||
try {
|
||||
fKeepPragmaPattern = Pattern.compile(keepPattern);
|
||||
} catch (PatternSyntaxException e) {
|
||||
fKeepPragmaPattern = Pattern.compile(CCorePreferenceConstants.DEFAULT_INCLUDE_KEEP_PATTERN);
|
||||
}
|
||||
}
|
||||
return fKeepPragmaPattern;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the effective translation unit location that overrides the default value obtained by
|
||||
* calling {@code getTranslationUnit().getLocation()}.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2013, 2014 Google, Inc and others.
|
||||
* Copyright (c) 2013, 2015 Google, Inc and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
|
@ -45,12 +45,14 @@ public class IncludePragmasBlock extends OptionsConfigurationBlock {
|
|||
private static final Key KEY_BEGIN_EXPORTS_PATTERN = getCDTCoreKey(CCorePreferenceConstants.INCLUDE_BEGIN_EXPORTS_PATTERN);
|
||||
private static final Key KEY_END_EXPORTS_PATTERN = getCDTCoreKey(CCorePreferenceConstants.INCLUDE_END_EXPORTS_PATTERN);
|
||||
private static final Key KEY_PRIVATE_PATTERN = getCDTCoreKey(CCorePreferenceConstants.INCLUDE_PRIVATE_PATTERN);
|
||||
private static final Key KEY_KEEP_PATTERN = getCDTCoreKey(CCorePreferenceConstants.INCLUDE_KEEP_PATTERN);
|
||||
|
||||
private static Key[] ALL_KEYS = {
|
||||
KEY_EXPORT_PATTERN,
|
||||
KEY_BEGIN_EXPORTS_PATTERN,
|
||||
KEY_END_EXPORTS_PATTERN,
|
||||
KEY_PRIVATE_PATTERN,
|
||||
KEY_KEEP_PATTERN,
|
||||
};
|
||||
private PixelConverter pixelConverter;
|
||||
|
||||
|
@ -83,9 +85,12 @@ public class IncludePragmasBlock extends OptionsConfigurationBlock {
|
|||
control = addTextField(composite, PreferencesMessages.IncludePragmasBlock_end_exports_pattern,
|
||||
KEY_END_EXPORTS_PATTERN, 0, pixelConverter.convertWidthInCharsToPixels(40));
|
||||
LayoutUtil.setHorizontalGrabbing(control, true);
|
||||
control = addTextField(composite, PreferencesMessages.IncludePragmasBlock_end_exports_pattern,
|
||||
control = addTextField(composite, PreferencesMessages.IncludePragmasBlock_private_pattern,
|
||||
KEY_PRIVATE_PATTERN, 0, pixelConverter.convertWidthInCharsToPixels(40));
|
||||
LayoutUtil.setHorizontalGrabbing(control, true);
|
||||
control = addTextField(composite, PreferencesMessages.IncludePragmasBlock_keep_pattern,
|
||||
KEY_KEEP_PATTERN, 0, pixelConverter.convertWidthInCharsToPixels(40));
|
||||
LayoutUtil.setHorizontalGrabbing(control, true);
|
||||
|
||||
updateControls();
|
||||
return composite;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2000, 2014 IBM Corporation and others.
|
||||
* Copyright (c) 2000, 2015 IBM Corporation and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
|
@ -469,6 +469,7 @@ public final class PreferencesMessages extends NLS {
|
|||
public static String IncludePragmasBlock_begin_exports_pattern;
|
||||
public static String IncludePragmasBlock_end_exports_pattern;
|
||||
public static String IncludePragmasBlock_private_pattern;
|
||||
public static String IncludePragmasBlock_keep_pattern;
|
||||
|
||||
public static String NameStylePreferencePage_title;
|
||||
public static String NameStyleBlock_code_node;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
###############################################################################
|
||||
# Copyright (c) 2000, 2014 IBM Corporation and others.
|
||||
# Copyright (c) 2000, 2015 IBM Corporation and others.
|
||||
# All rights reserved. This program and the accompanying materials
|
||||
# are made available under the terms of the Eclipse Public License v1.0
|
||||
# which accompanies this distribution, and is available at
|
||||
|
@ -522,10 +522,11 @@ IncludeOrderBlock_order_of_includes= O&rder of Include Statements:
|
|||
IncludePragmasPreferencePage_title= Include Pragmas
|
||||
IncludePragmasBlock_description=Include pragmas are special comments that affect behavior of Organize Includes command. A description of include pragmas can be found in <a href="https://code.google.com/p/include-what-you-use/wiki/IWYUPragmas">IWYU Pragmas</a>. Include patterns can be customized by defining regular expressions matching each of the pragmas.
|
||||
IncludePragmasBlock_link_tooltip=Wiki page describing include-what-you-use pragmas
|
||||
IncludePragmasBlock_export_pattern= &Export:
|
||||
IncludePragmasBlock_export_pattern= E&xport:
|
||||
IncludePragmasBlock_begin_exports_pattern= &Begin Exports:
|
||||
IncludePragmasBlock_end_exports_pattern= En&d Exports:
|
||||
IncludePragmasBlock_end_exports_pattern= &End Exports:
|
||||
IncludePragmasBlock_private_pattern= &Private:
|
||||
IncludePragmasBlock_keep_pattern= &Keep:
|
||||
|
||||
NameStylePreferencePage_title=Name Style
|
||||
NameStyleBlock_code_node=Code
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2012, 2013 Google, Inc and others.
|
||||
* Copyright (c) 2012, 2015 Google, Inc and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
|
@ -107,9 +107,9 @@ public class IncludeOrganizer {
|
|||
* {@code null} if the include was not resolved.
|
||||
*/
|
||||
IncludePrototype(IPath header, IncludeInfo includeInfo, IncludeGroupStyle style,
|
||||
IASTPreprocessorIncludeStatement existingInclude) {
|
||||
IASTPreprocessorIncludeStatement existingInclude, boolean required) {
|
||||
super(header, includeInfo, style, existingInclude);
|
||||
this.required = false;
|
||||
this.required = required;
|
||||
}
|
||||
|
||||
public boolean isRequired() {
|
||||
|
@ -195,6 +195,8 @@ public class IncludeOrganizer {
|
|||
List<InclusionRequest> requests = createInclusionRequests(ast, bindingsToInclude, false, reachableHeaders);
|
||||
processInclusionRequests(requests, headerSubstitutor);
|
||||
|
||||
NodeCommentMap commentedNodeMap = ASTCommenter.getCommentedNodeMap(ast);
|
||||
|
||||
// Use a map instead of a set to be able to retrieve existing elements using equal elements.
|
||||
// Maps each element to itself.
|
||||
Map<IncludePrototype, IncludePrototype> includePrototypes = new HashMap<>();
|
||||
|
@ -215,12 +217,12 @@ public class IncludeOrganizer {
|
|||
IPath header = path.isEmpty() ? null : Path.fromOSString(path);
|
||||
IncludeGroupStyle style =
|
||||
header != null ? fContext.getIncludeStyle(header) : fContext.getIncludeStyle(includeInfo);
|
||||
IncludePrototype prototype = new IncludePrototype(header, includeInfo, style, include);
|
||||
boolean required = hasPragmaKeep(include, commentedNodeMap);
|
||||
IncludePrototype prototype = new IncludePrototype(header, includeInfo, style, include, required);
|
||||
updateIncludePrototypes(includePrototypes, prototype);
|
||||
}
|
||||
}
|
||||
|
||||
NodeCommentMap commentedNodeMap = ASTCommenter.getCommentedNodeMap(ast);
|
||||
IRegion includeReplacementRegion =
|
||||
IncludeUtil.getSafeIncludeReplacementRegion(fContext.getSourceContents(), ast, commentedNodeMap);
|
||||
|
||||
|
@ -934,4 +936,31 @@ public class IncludeOrganizer {
|
|||
buf.append(lineComment);
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
private boolean hasPragmaKeep(IASTPreprocessorIncludeStatement include, NodeCommentMap commentedNodeMap) {
|
||||
List<IASTComment> comments = commentedNodeMap.getTrailingCommentsForNode(include);
|
||||
for (IASTComment comment : comments) {
|
||||
String text = getTrimmedCommentText(comment);
|
||||
if (fContext.getKeepPragmaPattern().matcher(text).matches())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private String getTrimmedCommentText(IASTComment comment) {
|
||||
char[] text = comment.getComment();
|
||||
int end = text.length - (comment.isBlockComment() ? 2 : 0);
|
||||
int begin;
|
||||
for (begin = 2; begin < end; begin++) {
|
||||
if (!Character.isWhitespace(text[begin]))
|
||||
break;
|
||||
}
|
||||
if (end <= begin)
|
||||
return ""; //$NON-NLS-1$
|
||||
while (--end >= begin) {
|
||||
if (!Character.isWhitespace(text[end]))
|
||||
break;
|
||||
}
|
||||
return new String(text, begin, end + 1 - begin);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue