| /* |
| * Copyright 2006 Sascha Weinreuter |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.intellij.plugins.intelliLang; |
| |
| import com.intellij.lang.Language; |
| import com.intellij.openapi.command.UndoConfirmationPolicy; |
| import com.intellij.openapi.command.WriteCommandAction; |
| import com.intellij.openapi.command.undo.GlobalUndoableAction; |
| import com.intellij.openapi.command.undo.UndoManager; |
| import com.intellij.openapi.command.undo.UndoableAction; |
| import com.intellij.openapi.components.*; |
| import com.intellij.openapi.diagnostic.Logger; |
| import com.intellij.openapi.extensions.Extensions; |
| import com.intellij.openapi.extensions.PluginDescriptor; |
| import com.intellij.openapi.project.Project; |
| import com.intellij.openapi.util.*; |
| import com.intellij.psi.PsiCompiledElement; |
| import com.intellij.psi.PsiElement; |
| import com.intellij.psi.PsiFile; |
| import com.intellij.psi.PsiLanguageInjectionHost; |
| import com.intellij.psi.util.CachedValue; |
| import com.intellij.psi.util.CachedValueProvider; |
| import com.intellij.psi.util.PsiUtilCore; |
| import com.intellij.util.*; |
| import com.intellij.util.containers.ConcurrentFactoryMap; |
| import com.intellij.util.containers.ContainerUtil; |
| import com.intellij.util.containers.Convertor; |
| import com.intellij.util.containers.MultiMap; |
| import gnu.trove.THashMap; |
| import gnu.trove.THashSet; |
| import org.intellij.plugins.intelliLang.inject.InjectorUtils; |
| import org.intellij.plugins.intelliLang.inject.LanguageInjectionConfigBean; |
| import org.intellij.plugins.intelliLang.inject.LanguageInjectionSupport; |
| import org.intellij.plugins.intelliLang.inject.config.BaseInjection; |
| import org.intellij.plugins.intelliLang.inject.config.InjectionPlace; |
| import org.jdom.Document; |
| import org.jdom.Element; |
| import org.jdom.JDOMException; |
| import org.jetbrains.annotations.NonNls; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.net.URL; |
| import java.util.*; |
| |
| /** |
| * Configuration that holds configured xml tag, attribute and method parameter |
| * injection settings as well as the annotations to use for injection, pattern |
| * validation and for substituting non-compile time constant expression. |
| * |
| * Making it a service may result in FileContentUtil.reparseFiles at a random loading moment which may cause |
| * mysterious PSI validity losses |
| */ |
| public class Configuration extends SimpleModificationTracker implements PersistentStateComponent<Element>, ModificationTracker { |
| static final Logger LOG = Logger.getInstance(Configuration.class.getName()); |
| private static final Condition<BaseInjection> LANGUAGE_INJECTION_CONDITION = new Condition<BaseInjection>() { |
| @Override |
| public boolean value(BaseInjection o) { |
| return Language.findLanguageByID(o.getInjectedLanguageId()) != null; |
| } |
| }; |
| |
| @State( |
| name = Configuration.COMPONENT_NAME, |
| storages = {@Storage( file = StoragePathMacros.APP_CONFIG + "/IntelliLang.xml", scheme = StorageScheme.DIRECTORY_BASED)}) |
| public static class App extends Configuration { |
| |
| private final List<BaseInjection> myDefaultInjections; |
| private final AdvancedConfiguration myAdvancedConfiguration; |
| |
| App() { |
| myDefaultInjections = loadDefaultInjections(); |
| myAdvancedConfiguration = new AdvancedConfiguration(); |
| } |
| |
| @Override |
| public List<BaseInjection> getDefaultInjections() { |
| return myDefaultInjections; |
| } |
| |
| @Override |
| public AdvancedConfiguration getAdvancedConfiguration() { |
| return myAdvancedConfiguration; |
| } |
| |
| @Override |
| public void loadState(final Element element) { |
| myAdvancedConfiguration.loadState(element); |
| super.loadState(element); |
| } |
| |
| @Override |
| public Element getState() { |
| final Element element = new Element(COMPONENT_NAME); |
| myAdvancedConfiguration.writeState(element); |
| return getState(element); |
| } |
| } |
| @State( |
| name = Configuration.COMPONENT_NAME, |
| storages = { |
| @Storage(file = StoragePathMacros.PROJECT_FILE), |
| @Storage(file = StoragePathMacros.PROJECT_CONFIG_DIR + "/IntelliLang.xml", scheme = StorageScheme.DIRECTORY_BASED) |
| }) |
| public static class Prj extends Configuration { |
| |
| private final Configuration myParentConfiguration; |
| |
| Prj(final Configuration configuration) { |
| myParentConfiguration = configuration; |
| } |
| |
| @Override |
| public AdvancedConfiguration getAdvancedConfiguration() { |
| return myParentConfiguration.getAdvancedConfiguration(); |
| } |
| |
| @Override |
| public List<BaseInjection> getDefaultInjections() { |
| return myParentConfiguration.getDefaultInjections(); |
| } |
| |
| @Override |
| protected Collection<BaseInjection> getAllInjections() { |
| Collection<BaseInjection> injections = super.getAllInjections(); |
| injections.addAll(myParentConfiguration.getAllInjections()); |
| return injections; |
| } |
| |
| @NotNull |
| @Override |
| public List<BaseInjection> getInjections(final String injectorId) { |
| return ContainerUtil.concat(myParentConfiguration.getInjections(injectorId), getOwnInjections(injectorId)); |
| } |
| |
| public Configuration getParentConfiguration() { |
| return myParentConfiguration; |
| } |
| |
| public List<BaseInjection> getOwnInjections(final String injectorId) { |
| return super.getInjections(injectorId); |
| } |
| |
| @Override |
| public long getModificationCount() { |
| return super.getModificationCount() + myParentConfiguration.getModificationCount(); |
| } |
| |
| public boolean replaceInjections(List<? extends BaseInjection> newInjections, |
| List<? extends BaseInjection> originalInjections, |
| boolean forceLevel) { |
| if (!forceLevel && !originalInjections.isEmpty()) { |
| if (myParentConfiguration.replaceInjections(Collections.<BaseInjection>emptyList(), originalInjections, false)) { |
| myParentConfiguration.replaceInjections(newInjections, Collections.<BaseInjection>emptyList(), false); |
| return true; |
| } |
| } |
| return super.replaceInjections(newInjections, originalInjections, forceLevel); |
| } |
| } |
| |
| public enum InstrumentationType { |
| NONE, ASSERT, EXCEPTION |
| } |
| |
| public enum DfaOption { |
| OFF, RESOLVE, ASSIGNMENTS, DFA |
| } |
| |
| @NonNls public static final String COMPONENT_NAME = "LanguageInjectionConfiguration"; |
| |
| // element names |
| @NonNls private static final String INSTRUMENTATION_TYPE_NAME = "INSTRUMENTATION"; |
| @NonNls private static final String LANGUAGE_ANNOTATION_NAME = "LANGUAGE_ANNOTATION"; |
| @NonNls private static final String PATTERN_ANNOTATION_NAME = "PATTERN_ANNOTATION"; |
| @NonNls private static final String SUBST_ANNOTATION_NAME = "SUBST_ANNOTATION"; |
| @NonNls private static final String RESOLVE_REFERENCES = "RESOLVE_REFERENCES"; |
| @NonNls private static final String LOOK_FOR_VAR_ASSIGNMENTS = "LOOK_FOR_VAR_ASSIGNMENTS"; |
| @NonNls private static final String USE_DFA_IF_AVAILABLE = "USE_DFA_IF_AVAILABLE"; |
| @NonNls private static final String INCLUDE_UNCOMPUTABLES_AS_LITERALS = "INCLUDE_UNCOMPUTABLES_AS_LITERALS"; |
| @NonNls private static final String SOURCE_MODIFICATION_ALLOWED = "SOURCE_MODIFICATION_ALLOWED"; |
| |
| private final Map<String, List<BaseInjection>> myInjections = new ConcurrentFactoryMap<String, List<BaseInjection>>() { |
| @Override |
| protected List<BaseInjection> create(final String key) { |
| return ContainerUtil.createLockFreeCopyOnWriteList(); |
| } |
| }; |
| |
| protected Collection<BaseInjection> getAllInjections() { |
| ArrayList<BaseInjection> injections = new ArrayList<BaseInjection>(); |
| for (List<BaseInjection> list : myInjections.values()) { |
| injections.addAll(list); |
| } |
| return injections; |
| } |
| |
| private CachedValue<MultiMap<String, BaseInjection>> myInjectionsById = new CachedValueImpl<MultiMap<String, BaseInjection>>(new CachedValueProvider<MultiMap<String, BaseInjection>>() { |
| @Nullable |
| @Override |
| public Result<MultiMap<String, BaseInjection>> compute() { |
| MultiMap<String, BaseInjection> map = new MultiMap<String, BaseInjection>(); |
| for (BaseInjection injection : getAllInjections()) { |
| map.putValue(injection.getInjectedLanguageId(), injection); |
| } |
| return Result.create(map, Configuration.this); |
| } |
| }); |
| |
| public Configuration() { |
| } |
| |
| public AdvancedConfiguration getAdvancedConfiguration() { |
| throw new UnsupportedOperationException("getAdvancedConfiguration should not be called"); |
| } |
| |
| public void loadState(final Element element) { |
| myInjections.clear(); |
| final THashMap<String, LanguageInjectionSupport> supports = new THashMap<String, LanguageInjectionSupport>(); |
| for (LanguageInjectionSupport support : InjectorUtils.getActiveInjectionSupports()) { |
| supports.put(support.getId(), support); |
| } |
| for (Element child : element.getChildren("injection")){ |
| final String key = child.getAttributeValue("injector-id"); |
| final LanguageInjectionSupport support = supports.get(key); |
| final BaseInjection injection = support == null ? new BaseInjection(key) : support.createInjection(child); |
| injection.loadState(child); |
| InjectionPlace[] places = dropKnownInvalidPlaces(injection.getInjectionPlaces()); |
| if (places != null) { // not all places were removed |
| injection.setInjectionPlaces(places); |
| myInjections.get(key).add(injection); |
| } |
| } |
| importPlaces(getDefaultInjections()); |
| } |
| |
| @Nullable |
| private static InjectionPlace[] dropKnownInvalidPlaces(InjectionPlace[] places) { |
| InjectionPlace[] result = places; |
| for (InjectionPlace place : places) { |
| if (place.getText().contains("matches(\"[^${}/\\\\]+\")")) { |
| result = ArrayUtil.remove(result, place); |
| } |
| } |
| return places.length != 0 && result.length == 0? null : result; |
| } |
| |
| private static boolean readBoolean(Element element, String key, boolean defValue) { |
| final String value = JDOMExternalizerUtil.readField(element, key); |
| if (value == null) return defValue; |
| return Boolean.parseBoolean(value); |
| } |
| |
| private static List<BaseInjection> loadDefaultInjections() { |
| final ArrayList<Configuration> cfgList = new ArrayList<Configuration>(); |
| final THashSet<Object> visited = new THashSet<Object>(); |
| for (LanguageInjectionConfigBean configBean : Extensions.getExtensions(LanguageInjectionSupport.CONFIG_EP_NAME)) { |
| PluginDescriptor descriptor = configBean.getPluginDescriptor(); |
| final ClassLoader loader = descriptor.getPluginClassLoader(); |
| try { |
| final Enumeration<URL> enumeration = loader.getResources(configBean.getConfigUrl()); |
| if (enumeration == null || !enumeration.hasMoreElements()) { |
| LOG.warn(descriptor.getPluginId() +": " + configBean.getConfigUrl() + " was not found"); |
| } |
| else { |
| while (enumeration.hasMoreElements()) { |
| URL url = enumeration.nextElement(); |
| if (!visited.add(url.getFile())) continue; // for DEBUG mode |
| try { |
| cfgList.add(load(url.openStream())); |
| } |
| catch (Exception e) { |
| LOG.warn(e); |
| } |
| } |
| } |
| } |
| catch (Exception e) { |
| LOG.warn(e); |
| } |
| } |
| |
| final ArrayList<BaseInjection> defaultInjections = new ArrayList<BaseInjection>(); |
| for (String supportId : InjectorUtils.getActiveInjectionSupportIds()) { |
| for (Configuration cfg : cfgList) { |
| final List<BaseInjection> imported = cfg.getInjections(supportId); |
| defaultInjections.addAll(imported); |
| } |
| } |
| return defaultInjections; |
| } |
| |
| public Element getState() { |
| return getState(new Element(COMPONENT_NAME)); |
| } |
| |
| protected Element getState(final Element element) { |
| Comparator<BaseInjection> comparator = new Comparator<BaseInjection>() { |
| public int compare(final BaseInjection o1, final BaseInjection o2) { |
| return Comparing.compare(o1.getDisplayName(), o2.getDisplayName()); |
| } |
| }; |
| List<String> injectorIds = new ArrayList<String>(myInjections.keySet()); |
| Collections.sort(injectorIds); |
| for (String key : injectorIds) { |
| TreeSet<BaseInjection> injections = new TreeSet<BaseInjection>(comparator); |
| injections.addAll(myInjections.get(key)); |
| injections.removeAll(getDefaultInjections()); |
| for (BaseInjection injection : injections) { |
| element.addContent(injection.getState()); |
| } |
| } |
| return element; |
| } |
| |
| public static Configuration getInstance() { |
| return ServiceManager.getService(Configuration.class); |
| } |
| |
| public static Configuration getProjectInstance(Project project) { |
| return ServiceManager.getService(project, Configuration.class); |
| } |
| |
| public List<BaseInjection> getDefaultInjections() { |
| return Collections.emptyList(); |
| } |
| |
| public Collection<BaseInjection> getInjectionsByLanguageId(String languageId) { |
| return myInjectionsById.getValue().get(languageId); |
| } |
| |
| @Nullable |
| public static Configuration load(final InputStream is) throws IOException, JDOMException { |
| try { |
| final Document document = JDOMUtil.loadDocument(is); |
| final ArrayList<Element> elements = new ArrayList<Element>(); |
| final Element rootElement = document.getRootElement(); |
| final Element state; |
| if (rootElement.getName().equals(COMPONENT_NAME)) { |
| state = rootElement; |
| } |
| else { |
| elements.add(rootElement); |
| //noinspection unchecked |
| elements.addAll(rootElement.getChildren("component")); |
| state = ContainerUtil.find(elements, new Condition<Element>() { |
| public boolean value(final Element element) { |
| return "component".equals(element.getName()) && COMPONENT_NAME.equals(element.getAttributeValue("name")); |
| } |
| }); |
| } |
| if (state != null) { |
| final Configuration cfg = new Configuration(); |
| cfg.loadState(state); |
| return cfg; |
| } |
| return null; |
| } |
| finally { |
| is.close(); |
| } |
| } |
| |
| private int importPlaces(final List<BaseInjection> injections) { |
| final Map<String, Set<BaseInjection>> map = ContainerUtil.classify(injections.iterator(), new Convertor<BaseInjection, String>() { |
| @Override |
| public String convert(final BaseInjection o) { |
| return o.getSupportId(); |
| } |
| }); |
| final ArrayList<BaseInjection> originalInjections = new ArrayList<BaseInjection>(); |
| final ArrayList<BaseInjection> newInjections = new ArrayList<BaseInjection>(); |
| for (String supportId : InjectorUtils.getActiveInjectionSupportIds()) { |
| final Set<BaseInjection> importingInjections = map.get(supportId); |
| if (importingInjections == null) continue; |
| importInjections(getInjections(supportId), importingInjections, originalInjections, newInjections); |
| } |
| if (!newInjections.isEmpty()) configurationModified(); |
| replaceInjections(newInjections, originalInjections, true); |
| return newInjections.size(); |
| } |
| |
| static void importInjections(final Collection<BaseInjection> existingInjections, final Collection<BaseInjection> importingInjections, |
| final Collection<BaseInjection> originalInjections, final Collection<BaseInjection> newInjections) { |
| final MultiValuesMap<InjectionPlace, BaseInjection> placeMap = new MultiValuesMap<InjectionPlace, BaseInjection>(); |
| for (BaseInjection exising : existingInjections) { |
| for (InjectionPlace place : exising.getInjectionPlaces()) { |
| placeMap.put(place, exising); |
| } |
| } |
| main: for (BaseInjection other : importingInjections) { |
| final List<BaseInjection> matchingInjections = ContainerUtil.concat(other.getInjectionPlaces(), new Function<InjectionPlace, Collection<? extends BaseInjection>>() { |
| public Collection<? extends BaseInjection> fun(final InjectionPlace o) { |
| final Collection<BaseInjection> collection = placeMap.get(o); |
| return collection == null? Collections.<BaseInjection>emptyList() : collection; |
| } |
| }); |
| if (matchingInjections.isEmpty()) { |
| newInjections.add(other); |
| } |
| else { |
| BaseInjection existing = null; |
| for (BaseInjection injection : matchingInjections) { |
| if (injection.equals(other)) continue main; |
| if (existing == null && injection.sameLanguageParameters(other)) { |
| existing = injection; |
| } |
| } |
| if (existing == null) continue main; // skip!! language changed |
| final BaseInjection newInjection = existing.copy(); |
| newInjection.mergeOriginalPlacesFrom(other, true); |
| if (!newInjection.equals(existing)) { |
| originalInjections.add(existing); |
| newInjections.add(newInjection); |
| } |
| } |
| } |
| } |
| |
| private void configurationModified() { |
| incModificationCount(); |
| } |
| |
| @Nullable |
| public BaseInjection findExistingInjection(@NotNull final BaseInjection injection) { |
| final List<BaseInjection> list = getInjections(injection.getSupportId()); |
| for (BaseInjection cur : list) { |
| if (cur.intersectsWith(injection)) return cur; |
| } |
| return null; |
| } |
| |
| public boolean setHostInjectionEnabled(final PsiLanguageInjectionHost host, final Collection<String> languages, final boolean enabled) { |
| final ArrayList<BaseInjection> originalInjections = new ArrayList<BaseInjection>(); |
| final ArrayList<BaseInjection> newInjections = new ArrayList<BaseInjection>(); |
| for (LanguageInjectionSupport support : InjectorUtils.getActiveInjectionSupports()) { |
| for (BaseInjection injection : getInjections(support.getId())) { |
| if (!languages.contains(injection.getInjectedLanguageId())) continue; |
| boolean replace = false; |
| final ArrayList<InjectionPlace> newPlaces = new ArrayList<InjectionPlace>(); |
| for (InjectionPlace place : injection.getInjectionPlaces()) { |
| if (place.isEnabled() != enabled && place.getElementPattern() != null && |
| (place.getElementPattern().accepts(host) || place.getElementPattern().accepts(host.getParent()))) { |
| newPlaces.add(place.enabled(enabled)); |
| replace = true; |
| } |
| else newPlaces.add(place); |
| } |
| if (replace) { |
| originalInjections.add(injection); |
| final BaseInjection newInjection = injection.copy(); |
| newInjection.setInjectionPlaces(newPlaces.toArray(new InjectionPlace[newPlaces.size()])); |
| newInjections.add(newInjection); |
| } |
| } |
| } |
| if (!originalInjections.isEmpty()) { |
| replaceInjectionsWithUndo(host.getProject(), newInjections, originalInjections, Collections.<PsiElement>emptyList()); |
| return true; |
| } |
| return false; |
| } |
| |
| protected void setInjections(Collection<BaseInjection> injections) { |
| for (BaseInjection injection : injections) { |
| myInjections.get(injection.getSupportId()).add(injection); |
| } |
| } |
| |
| /** |
| * @param injectorId see {@link org.intellij.plugins.intelliLang.inject.LanguageInjectionSupport#getId()} |
| */ |
| @NotNull |
| public List<BaseInjection> getInjections(final String injectorId) { |
| return Collections.unmodifiableList(myInjections.get(injectorId)); |
| } |
| |
| public void replaceInjectionsWithUndo(final Project project, |
| final List<? extends BaseInjection> newInjections, |
| final List<? extends BaseInjection> originalInjections, |
| final List<? extends PsiElement> psiElementsToRemove) { |
| replaceInjectionsWithUndo(project, newInjections, originalInjections, psiElementsToRemove, |
| new PairProcessor<List<? extends BaseInjection>, List<? extends BaseInjection>>() { |
| public boolean process(final List<? extends BaseInjection> add, |
| final List<? extends BaseInjection> remove) { |
| replaceInjectionsWithUndoInner(add, remove); |
| if (ContainerUtil.find(add, LANGUAGE_INJECTION_CONDITION) != null || ContainerUtil.find(remove, |
| LANGUAGE_INJECTION_CONDITION) != null) { |
| FileContentUtil.reparseOpenedFiles(); |
| } |
| return true; |
| } |
| }); |
| } |
| |
| protected void replaceInjectionsWithUndoInner(final List<? extends BaseInjection> add, final List<? extends BaseInjection> remove) { |
| replaceInjections(add, remove, false); |
| } |
| |
| public static <T> void replaceInjectionsWithUndo(final Project project, final T add, final T remove, |
| final List<? extends PsiElement> psiElementsToRemove, |
| final PairProcessor<T, T> actualProcessor) { |
| final UndoableAction action = new GlobalUndoableAction() { |
| public void undo() { |
| actualProcessor.process(remove, add); |
| } |
| |
| public void redo() { |
| actualProcessor.process(add, remove); |
| } |
| }; |
| final List<PsiFile> psiFiles = ContainerUtil.mapNotNull(psiElementsToRemove, new NullableFunction<PsiElement, PsiFile>() { |
| public PsiFile fun(final PsiElement psiAnnotation) { |
| return psiAnnotation instanceof PsiCompiledElement ? null : psiAnnotation.getContainingFile(); |
| } |
| }); |
| new WriteCommandAction.Simple(project, "Language Injection Configuration Update", PsiUtilCore.toPsiFileArray(psiFiles)) { |
| public void run() { |
| for (PsiElement annotation : psiElementsToRemove) { |
| annotation.delete(); |
| } |
| actualProcessor.process(add, remove); |
| UndoManager.getInstance(project).undoableActionPerformed(action); |
| } |
| |
| @Override |
| protected UndoConfirmationPolicy getUndoConfirmationPolicy() { |
| return UndoConfirmationPolicy.REQUEST_CONFIRMATION; |
| } |
| }.execute(); |
| } |
| |
| public boolean replaceInjections(List<? extends BaseInjection> newInjections, |
| List<? extends BaseInjection> originalInjections, |
| boolean forceLevel) { |
| boolean changed = false; |
| for (BaseInjection injection : originalInjections) { |
| changed |= myInjections.get(injection.getSupportId()).remove(injection); |
| } |
| for (BaseInjection injection : newInjections) { |
| changed |= myInjections.get(injection.getSupportId()).add(injection); |
| } |
| if (changed) { |
| configurationModified(); |
| } |
| return changed; |
| } |
| |
| public static class AdvancedConfiguration { |
| // runtime pattern validation instrumentation |
| @NotNull private InstrumentationType myInstrumentationType = InstrumentationType.ASSERT; |
| |
| // annotation class names |
| @NotNull private String myLanguageAnnotation; |
| @NotNull private String myPatternAnnotation; |
| @NotNull private String mySubstAnnotation; |
| |
| private boolean myIncludeUncomputablesAsLiterals; |
| private DfaOption myDfaOption = DfaOption.RESOLVE; |
| private boolean mySourceModificationAllowed; |
| |
| // cached annotation name pairs |
| private Pair<String, ? extends Set<String>> myLanguageAnnotationPair; |
| private Pair<String, ? extends Set<String>> myPatternAnnotationPair; |
| |
| private Pair<String, ? extends Set<String>> mySubstAnnotationPair; |
| |
| public AdvancedConfiguration() { |
| setLanguageAnnotation("org.intellij.lang.annotations.Language"); |
| setPatternAnnotation("org.intellij.lang.annotations.Pattern"); |
| setSubstAnnotation("org.intellij.lang.annotations.Subst"); |
| } |
| |
| public String getLanguageAnnotationClass() { |
| return myLanguageAnnotation; |
| } |
| |
| public String getPatternAnnotationClass() { |
| return myPatternAnnotation; |
| } |
| |
| public String getSubstAnnotationClass() { |
| return mySubstAnnotation; |
| } |
| |
| public void setInstrumentationType(@Nullable String type) { |
| if (type != null) { |
| setInstrumentationType(InstrumentationType.valueOf(type)); |
| } |
| } |
| |
| public void setInstrumentationType(@NotNull InstrumentationType type) { |
| myInstrumentationType = type; |
| } |
| |
| public void setLanguageAnnotation(@Nullable String languageAnnotation) { |
| if (languageAnnotation == null) return; |
| myLanguageAnnotation = languageAnnotation; |
| myLanguageAnnotationPair = Pair.create(languageAnnotation, Collections.singleton(languageAnnotation)); |
| } |
| |
| public Pair<String, ? extends Set<String>> getLanguageAnnotationPair() { |
| return myLanguageAnnotationPair; |
| } |
| |
| public void setPatternAnnotation(@Nullable String patternAnnotation) { |
| if (patternAnnotation == null) return; |
| myPatternAnnotation = patternAnnotation; |
| myPatternAnnotationPair = Pair.create(patternAnnotation, Collections.singleton(patternAnnotation)); |
| } |
| |
| public Pair<String, ? extends Set<String>> getPatternAnnotationPair() { |
| return myPatternAnnotationPair; |
| } |
| |
| public void setSubstAnnotation(@Nullable String substAnnotation) { |
| if (substAnnotation == null) return; |
| mySubstAnnotation = substAnnotation; |
| mySubstAnnotationPair = Pair.create(substAnnotation, Collections.singleton(substAnnotation)); |
| } |
| |
| public Pair<String, ? extends Set<String>> getSubstAnnotationPair() { |
| return mySubstAnnotationPair; |
| } |
| |
| public boolean isIncludeUncomputablesAsLiterals() { |
| return myIncludeUncomputablesAsLiterals; |
| } |
| |
| public void setIncludeUncomputablesAsLiterals(boolean flag) { |
| myIncludeUncomputablesAsLiterals = flag; |
| } |
| |
| @NotNull |
| public DfaOption getDfaOption() { |
| return myDfaOption; |
| } |
| |
| public void setDfaOption(@NotNull final DfaOption dfaOption) { |
| myDfaOption = dfaOption; |
| } |
| |
| public boolean isSourceModificationAllowed() { |
| return mySourceModificationAllowed; |
| } |
| |
| public void setSourceModificationAllowed(boolean sourceModificationAllowed) { |
| mySourceModificationAllowed = sourceModificationAllowed; |
| } |
| |
| public InstrumentationType getInstrumentation() { |
| return myInstrumentationType; |
| } |
| |
| private void writeState(final Element element) { |
| JDOMExternalizerUtil.writeField(element, INSTRUMENTATION_TYPE_NAME, myInstrumentationType.toString()); |
| JDOMExternalizerUtil.writeField(element, LANGUAGE_ANNOTATION_NAME, myLanguageAnnotation); |
| JDOMExternalizerUtil.writeField(element, PATTERN_ANNOTATION_NAME, myPatternAnnotation); |
| JDOMExternalizerUtil.writeField(element, SUBST_ANNOTATION_NAME, mySubstAnnotation); |
| if (myIncludeUncomputablesAsLiterals) { |
| JDOMExternalizerUtil.writeField(element, INCLUDE_UNCOMPUTABLES_AS_LITERALS, "true"); |
| } |
| if (mySourceModificationAllowed) { |
| JDOMExternalizerUtil.writeField(element, SOURCE_MODIFICATION_ALLOWED, "true"); |
| } |
| switch (myDfaOption) { |
| case OFF: |
| break; |
| case RESOLVE: |
| JDOMExternalizerUtil.writeField(element, RESOLVE_REFERENCES, Boolean.TRUE.toString()); |
| break; |
| case ASSIGNMENTS: |
| JDOMExternalizerUtil.writeField(element, LOOK_FOR_VAR_ASSIGNMENTS, Boolean.TRUE.toString()); |
| break; |
| case DFA: |
| JDOMExternalizerUtil.writeField(element, USE_DFA_IF_AVAILABLE, Boolean.TRUE.toString()); |
| break; |
| } |
| } |
| |
| private void loadState(final Element element) { |
| setInstrumentationType(JDOMExternalizerUtil.readField(element, INSTRUMENTATION_TYPE_NAME)); |
| setLanguageAnnotation(JDOMExternalizerUtil.readField(element, LANGUAGE_ANNOTATION_NAME)); |
| setPatternAnnotation(JDOMExternalizerUtil.readField(element, PATTERN_ANNOTATION_NAME)); |
| setSubstAnnotation(JDOMExternalizerUtil.readField(element, SUBST_ANNOTATION_NAME)); |
| if (readBoolean(element, RESOLVE_REFERENCES, true)) { |
| setDfaOption(DfaOption.RESOLVE); |
| } |
| if (readBoolean(element, LOOK_FOR_VAR_ASSIGNMENTS, false)) { |
| setDfaOption(DfaOption.ASSIGNMENTS); |
| } |
| if (readBoolean(element, USE_DFA_IF_AVAILABLE, false)) { |
| setDfaOption(DfaOption.DFA); |
| } |
| setIncludeUncomputablesAsLiterals(readBoolean(element, INCLUDE_UNCOMPUTABLES_AS_LITERALS, false)); |
| setSourceModificationAllowed(readBoolean(element, SOURCE_MODIFICATION_ALLOWED, false)); |
| } |
| } |
| } |