diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/AbstractDBTraceSymbol.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/AbstractDBTraceSymbol.java
index 32ad634f22..2479a0a84e 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/AbstractDBTraceSymbol.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/AbstractDBTraceSymbol.java
@@ -52,7 +52,7 @@ import ghidra.util.task.TaskMonitor;
public abstract class AbstractDBTraceSymbol extends DBAnnotatedObject
implements TraceSymbol, DecodesAddresses {
- private static final byte SOURCE_MASK = 0x0F;
+ private static final byte SOURCE_MASK = 0x0F; // see SourceType
private static final int SOURCE_SHIFT = 0;
private static final byte SOURCE_CLEAR = ~(SOURCE_MASK << SOURCE_SHIFT);
@@ -311,7 +311,7 @@ public abstract class AbstractDBTraceSymbol extends DBAnnotatedObject
public DBTraceReference[] getReferences() {
return getReferences(TaskMonitor.DUMMY);
}
-
+
@SuppressWarnings("hiding")
void rawSet(String name, long parentID) {
this.name = name;
@@ -365,8 +365,8 @@ public abstract class AbstractDBTraceSymbol extends DBAnnotatedObject
}
protected void doSetSource(SourceType newSource) {
- flags =
- (byte) ((flags & SOURCE_CLEAR) | (newSource.ordinal() & SOURCE_MASK) << SOURCE_SHIFT);
+ flags = (byte) ((flags & SOURCE_CLEAR) |
+ (newSource.getStorageId() & SOURCE_MASK) << SOURCE_SHIFT);
}
/**
@@ -502,7 +502,7 @@ public abstract class AbstractDBTraceSymbol extends DBAnnotatedObject
@Override
public SourceType getSource() {
assertNotGlobal();
- return SourceType.values()[(flags >> SOURCE_SHIFT) & SOURCE_MASK];
+ return SourceType.getSourceType((flags >> SOURCE_SHIFT) & SOURCE_MASK);
}
@Override
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceReferenceSpace.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceReferenceSpace.java
index cdb57199de..9e25bbd199 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceReferenceSpace.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceReferenceSpace.java
@@ -103,14 +103,14 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS
implements DecodesAddresses {
private static final String TABLE_NAME = "References";
- private static final byte SOURCE_MASK = 0x0F;
+ private static final byte SOURCE_MASK = 0x0F; // see SourceType
private static final byte SOURCE_SHIFT = 0;
//private static final byte SOURCE_CLEAR = ~(SOURCE_MASK << SOURCE_SHIFT);
private static final byte PRIMARY_MASK = 0x10;
private static final byte PRIMARY_CLEAR = ~PRIMARY_MASK;
- private static final byte TYPE_MASK = 0x3;
+ private static final byte TYPE_MASK = 0x3; // See DBTraceReferenceSpace.TypeEnum
private static final byte TYPE_SHIFT = 5;
//private static final byte TYPE_CLEAR = ~(TYPE_MASK << TYPE_SHIFT);
@@ -142,15 +142,9 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS
return DBTraceUtils.tableName(TABLE_NAME, space);
}
- @DBAnnotatedField(
- column = TO_ADDR_MIN_COLUMN_NAME,
- indexed = true,
- codec = AddressDBFieldCodec.class)
+ @DBAnnotatedField(column = TO_ADDR_MIN_COLUMN_NAME, indexed = true, codec = AddressDBFieldCodec.class)
protected Address toAddrMin = Address.NO_ADDRESS;
- @DBAnnotatedField(
- column = TO_ADDR_MAX_COLUMN_NAME,
- indexed = true,
- codec = AddressDBFieldCodec.class)
+ @DBAnnotatedField(column = TO_ADDR_MAX_COLUMN_NAME, indexed = true, codec = AddressDBFieldCodec.class)
protected Address toAddrMax = Address.NO_ADDRESS;
@DBAnnotatedField(column = SYMBOL_ID_COLUMN_NAME, indexed = true)
protected long symbolId; // TODO: Is this at the from or to address? I think TO...
@@ -201,8 +195,8 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS
return this;
}
- protected void set(AddressRange toRange, long symbolId, RefType refType,
- int opIndex, long ext, boolean isPrimary, TypeEnum type, SourceType sourceType) {
+ protected void set(AddressRange toRange, long symbolId, RefType refType, int opIndex,
+ long ext, boolean isPrimary, TypeEnum type, SourceType sourceType) {
this.toAddrMin = toRange.getMinAddress();
this.toAddrMax = toRange.getMaxAddress();
this.symbolId = symbolId;
@@ -210,7 +204,7 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS
this.opIndex = (byte) opIndex;
this.ext = ext;
this.flags = (byte) ((isPrimary ? PRIMARY_MASK : 0) |
- (sourceType.ordinal() << SOURCE_SHIFT) | type.ordinal() << TYPE_SHIFT);
+ (sourceType.getStorageId() << SOURCE_SHIFT) | type.ordinal() << TYPE_SHIFT);
update(TO_ADDR_MIN_COLUMN, TO_ADDR_MAX_COLUMN, SYMBOL_ID_COLUMN, REF_TYPE_COLUMN,
OP_INDEX_COLUMN, EXT_COLUMN, FLAGS_COLUMN);
@@ -243,8 +237,8 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS
TraceEvents.SYMBOL_ASSOCIATION_REMOVED, space.space, oldSymbol, ref));
}
if (newSymbol != null) {
- space.trace.setChanged(new TraceChangeRecord<>(
- TraceEvents.SYMBOL_ASSOCIATION_ADDED, space.space, newSymbol, ref));
+ space.trace.setChanged(new TraceChangeRecord<>(TraceEvents.SYMBOL_ASSOCIATION_ADDED,
+ space.space, newSymbol, ref));
}
}
@@ -276,7 +270,7 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS
}
public SourceType getSourceType() {
- return SourceType.values()[(flags >> SOURCE_SHIFT) & SOURCE_MASK];
+ return SourceType.getSourceType((flags >> SOURCE_SHIFT) & SOURCE_MASK);
}
protected void doDelete() {
@@ -375,16 +369,15 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS
referenceMapSpace.getUserIndex(long.class, DBTraceReferenceEntry.SYMBOL_ID_COLUMN);
this.xrefMapSpace = new DBTraceAddressSnapRangePropertyMapSpace<>(
- DBTraceXRefEntry.tableName(space), trace, factory, lock, space,
- DBTraceXRefEntry.class, (t, s, r) -> new DBTraceXRefEntry(this, t, s, r));
+ DBTraceXRefEntry.tableName(space), trace, factory, lock, space, DBTraceXRefEntry.class,
+ (t, s, r) -> new DBTraceXRefEntry(this, t, s, r));
this.xrefsByRefKey = xrefMapSpace.getUserIndex(long.class, DBTraceXRefEntry.REF_KEY_COLUMN);
}
protected void doAddXRef(DBTraceReferenceEntry refEnt) {
// Note: called from manager on relevant space
DBTraceXRefEntry xrefEnt = xrefMapSpace.put(refEnt.toRange, refEnt.getLifespan(), null);
- xrefEnt.set((short) refEnt.getRange().getAddressSpace().getSpaceID(),
- refEnt.getKey());
+ xrefEnt.set((short) refEnt.getRange().getAddressSpace().getSpaceID(), refEnt.getKey());
}
protected void doDelXRef(DBTraceReferenceEntry refEnt) {
@@ -451,11 +444,11 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS
int operandIndex) {
// Do I consider "compatibility?" as in ReferenceDBManager?
// NOTE: Always call with the write lock
- for (DBTraceReferenceEntry ent : referenceMapSpace.reduce(
- TraceAddressSnapRangeQuery.intersecting(new AddressRangeImpl(fromAddress, fromAddress),
- span)).values()) {
- if (!ent.toRange.equals(toRange) ||
- ent.opIndex != operandIndex) {
+ for (DBTraceReferenceEntry ent : referenceMapSpace
+ .reduce(TraceAddressSnapRangeQuery
+ .intersecting(new AddressRangeImpl(fromAddress, fromAddress), span))
+ .values()) {
+ if (!ent.toRange.equals(toRange) || ent.opIndex != operandIndex) {
continue;
}
@@ -585,10 +578,10 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS
public DBTraceReference getReference(long snap, Address fromAddress, AddressRange toRange,
int operandIndex) {
try (LockHold hold = LockHold.lock(lock.readLock())) {
- for (DBTraceReferenceEntry entry : referenceMapSpace.reduce(
- TraceAddressSnapRangeQuery.at(fromAddress, snap)).values()) {
- if (!entry.toRange.equals(toRange) ||
- entry.opIndex != operandIndex) {
+ for (DBTraceReferenceEntry entry : referenceMapSpace
+ .reduce(TraceAddressSnapRangeQuery.at(fromAddress, snap))
+ .values()) {
+ if (!entry.toRange.equals(toRange) || entry.opIndex != operandIndex) {
continue;
}
return entry.ref;
@@ -641,8 +634,7 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS
@Override
public Collection extends DBTraceReference> getFlowReferencesFrom(long snap,
Address fromAddress) {
- return streamReferencesFrom(snap, fromAddress)
- .filter(r -> r.getReferenceType().isFlow())
+ return streamReferencesFrom(snap, fromAddress).filter(r -> r.getReferenceType().isFlow())
.toList();
}
@@ -650,8 +642,9 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS
public void clearReferencesFrom(Lifespan span, AddressRange range) {
try (LockHold hold = manager.getTrace().lockWrite()) {
long startSnap = span.lmin();
- for (DBTraceReferenceEntry ref : referenceMapSpace.reduce(
- TraceAddressSnapRangeQuery.intersecting(range, span)).values()) {
+ for (DBTraceReferenceEntry ref : referenceMapSpace
+ .reduce(TraceAddressSnapRangeQuery.intersecting(range, span))
+ .values()) {
truncateOrDeleteEntry(ref, startSnap);
}
// TODO: Coalesce events?
@@ -682,21 +675,19 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS
@Override
public Collection extends DBTraceReference> getReferencesToRange(Lifespan span,
AddressRange range, Rectangle2DDirection order) {
- return new LazyCollection<>(
- () -> xrefMapSpace
- .reduce(TraceAddressSnapRangeQuery.intersecting(range, span).starting(order))
- .values()
- .stream()
- .map(this::getRefForXRefEntry));
+ return new LazyCollection<>(() -> xrefMapSpace
+ .reduce(TraceAddressSnapRangeQuery.intersecting(range, span).starting(order))
+ .values()
+ .stream()
+ .map(this::getRefForXRefEntry));
}
protected void truncateOrDeleteEntry(DBTraceReferenceEntry ref, long otherStartSnap) {
if (ref.getLifespan().lmin() < otherStartSnap) {
Lifespan oldSpan = ref.getLifespan();
ref.setEndSnap(otherStartSnap - 1);
- trace.setChanged(new TraceChangeRecord<>(
- TraceEvents.REFERENCE_LIFESPAN_CHANGED, space, ref.ref, oldSpan,
- ref.getLifespan()));
+ trace.setChanged(new TraceChangeRecord<>(TraceEvents.REFERENCE_LIFESPAN_CHANGED, space,
+ ref.ref, oldSpan, ref.getLifespan()));
}
else {
ref.ref.delete();
@@ -707,8 +698,9 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS
public void clearReferencesTo(Lifespan span, AddressRange range) {
try (LockHold hold = manager.getTrace().lockWrite()) {
long startSnap = span.lmin();
- for (DBTraceXRefEntry xref : xrefMapSpace.reduce(
- TraceAddressSnapRangeQuery.intersecting(range, span)).values()) {
+ for (DBTraceXRefEntry xref : xrefMapSpace
+ .reduce(TraceAddressSnapRangeQuery.intersecting(range, span))
+ .values()) {
DBTraceReferenceEntry ref = getRefEntryForXRefEntry(xref);
truncateOrDeleteEntry(ref, startSnap);
}
diff --git a/Ghidra/Features/Base/src/main/help/help/topics/CodeBrowserPlugin/Browser_Field_Formatter.htm b/Ghidra/Features/Base/src/main/help/help/topics/CodeBrowserPlugin/Browser_Field_Formatter.htm
index 1dc739a1da..50904aa6aa 100644
--- a/Ghidra/Features/Base/src/main/help/help/topics/CodeBrowserPlugin/Browser_Field_Formatter.htm
+++ b/Ghidra/Features/Base/src/main/help/help/topics/CodeBrowserPlugin/Browser_Field_Formatter.htm
@@ -448,7 +448,7 @@
Function |
Indicates the source-type associated with the
- function signature (i.e., DEFAULT, ANALYSIS, IMPORTED, USER_DEFINED). |
+ function signature (i.e., DEFAULT, AI_ASSIST, ANALYSIS, IMPORTED, USER_DEFINED).
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symtable/NewSymbolFilter.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symtable/NewSymbolFilter.java
index 10a72d096a..2cda64dea8 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symtable/NewSymbolFilter.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symtable/NewSymbolFilter.java
@@ -4,9 +4,9 @@
* 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.
@@ -29,11 +29,12 @@ public class NewSymbolFilter implements SymbolFilter {
private static final String XML_NAME = "SYMBOL_TABLE_FILTER";
- private Filter userDefinedFilter;
- private Filter analysisFilter;
- private Filter defaultFunctionFilter;
- private Filter defaultLabelFilter;
- private Filter importedFilter;
+ private Filter defaultLabelSourceFilter;
+ private Filter defaultFunctionSourceFilter;
+ private Filter aiSourceFilter;
+ private Filter analysisSourceFilter;
+ private Filter importedSourceFilter;
+ private Filter userDefinedSourceFilter;
private Filter[] labelFilters;
private Filter[] nonLabelFilters;
@@ -67,19 +68,21 @@ public class NewSymbolFilter implements SymbolFilter {
for (Filter advancedFilter : advancedFilters) {
filterMap.put(advancedFilter.getName(), advancedFilter);
}
- filterMap.put(userDefinedFilter.getName(), userDefinedFilter);
- filterMap.put(importedFilter.getName(), importedFilter);
- filterMap.put(analysisFilter.getName(), analysisFilter);
- filterMap.put(defaultLabelFilter.getName(), defaultLabelFilter);
- filterMap.put(defaultFunctionFilter.getName(), defaultFunctionFilter);
+ filterMap.put(defaultLabelSourceFilter.getName(), defaultLabelSourceFilter);
+ filterMap.put(defaultFunctionSourceFilter.getName(), defaultFunctionSourceFilter);
+ filterMap.put(aiSourceFilter.getName(), aiSourceFilter);
+ filterMap.put(analysisSourceFilter.getName(), analysisSourceFilter);
+ filterMap.put(importedSourceFilter.getName(), importedSourceFilter);
+ filterMap.put(userDefinedSourceFilter.getName(), userDefinedSourceFilter);
if (oldFilter instanceof NewSymbolFilter) {
NewSymbolFilter filter = (NewSymbolFilter) oldFilter;
- userDefinedFilter.setActive(filter.userDefinedFilter.isActive());
- importedFilter.setActive(filter.importedFilter.isActive());
- analysisFilter.setActive(filter.analysisFilter.isActive());
- defaultLabelFilter.setActive(filter.defaultLabelFilter.isActive());
- defaultFunctionFilter.setActive(filter.defaultFunctionFilter.isActive());
+ defaultLabelSourceFilter.setActive(filter.defaultLabelSourceFilter.isActive());
+ defaultFunctionSourceFilter.setActive(filter.defaultFunctionSourceFilter.isActive());
+ aiSourceFilter.setActive(filter.aiSourceFilter.isActive());
+ analysisSourceFilter.setActive(filter.analysisSourceFilter.isActive());
+ importedSourceFilter.setActive(filter.importedSourceFilter.isActive());
+ userDefinedSourceFilter.setActive(filter.userDefinedSourceFilter.isActive());
for (int i = 0; i < labelFilters.length; i++) {
labelFilters[i].setActive(filter.labelFilters[i].isActive());
@@ -156,8 +159,8 @@ public class NewSymbolFilter implements SymbolFilter {
@Override
public boolean acceptsOnlyCodeSymbols() {
- for (int i = 0; i < activeTypeFilters.length; i++) {
- if (!activeTypeFilters[i].onlyCodeSymbols) {
+ for (Filter activeTypeFilter : activeTypeFilters) {
+ if (!activeTypeFilter.onlyCodeSymbols) {
return false;
}
}
@@ -166,7 +169,7 @@ public class NewSymbolFilter implements SymbolFilter {
@Override
public boolean acceptsDefaultLabelSymbols() {
- if (!defaultLabelFilter.isActive()) {
+ if (!defaultLabelSourceFilter.isActive()) {
return false;
}
for (Filter activeTypeFilter : activeTypeFilters) {
@@ -183,10 +186,10 @@ public class NewSymbolFilter implements SymbolFilter {
}
String[] getSourceFilterNames() {
- return new String[] { userDefinedFilter.getName(), defaultFunctionFilter.getName(),
- importedFilter.getName(), defaultLabelFilter.getName(), analysisFilter.getName(),
-
- };
+ return new String[] { defaultLabelSourceFilter.getName(),
+ defaultFunctionSourceFilter.getName(), aiSourceFilter.getName(),
+ analysisSourceFilter.getName(), userDefinedSourceFilter.getName(),
+ importedSourceFilter.getName() };
}
String[] getLabelTypeFilterNames() {
@@ -283,31 +286,38 @@ public class NewSymbolFilter implements SymbolFilter {
for (Filter advancedFilter : advancedFilters) {
advancedFilter.setActive(false);
}
- userDefinedFilter.setActive(true);
- importedFilter.setActive(true);
- analysisFilter.setActive(true);
- defaultFunctionFilter.setActive(true);
- defaultLabelFilter.setActive(false);
+ defaultFunctionSourceFilter.setActive(true);
+ defaultLabelSourceFilter.setActive(false);
+ aiSourceFilter.setActive(true);
+ analysisSourceFilter.setActive(true);
+ importedSourceFilter.setActive(true);
+ userDefinedSourceFilter.setActive(true);
+
rebuildActiveFilters();
}
private void rebuildActiveFilters() {
ArrayList originList = new ArrayList<>(3);
- if (userDefinedFilter.isActive()) {
- originList.add(userDefinedFilter);
+
+ if (defaultLabelSourceFilter.isActive()) {
+ originList.add(defaultLabelSourceFilter);
}
- if (importedFilter.isActive()) {
- originList.add(importedFilter);
+ if (defaultFunctionSourceFilter.isActive()) {
+ originList.add(defaultFunctionSourceFilter);
}
- if (analysisFilter.isActive()) {
- originList.add(analysisFilter);
+ if (aiSourceFilter.isActive()) {
+ originList.add(aiSourceFilter);
}
- if (defaultLabelFilter.isActive()) {
- originList.add(defaultLabelFilter);
+ if (analysisSourceFilter.isActive()) {
+ originList.add(analysisSourceFilter);
}
- if (defaultFunctionFilter.isActive()) {
- originList.add(defaultFunctionFilter);
+ if (importedSourceFilter.isActive()) {
+ originList.add(importedSourceFilter);
}
+ if (userDefinedSourceFilter.isActive()) {
+ originList.add(userDefinedSourceFilter);
+ }
+
activeOriginFilters = new Filter[originList.size()];
originList.toArray(activeOriginFilters);
@@ -339,49 +349,16 @@ public class NewSymbolFilter implements SymbolFilter {
advancedList.toArray(activeAdvancedFilters);
acceptsAllTypes = activeTypeFilters.length == labelFilters.length + nonLabelFilters.length;
- acceptsAllSources = userDefinedFilter.isActive() && analysisFilter.isActive() &&
- defaultLabelFilter.isActive() && defaultFunctionFilter.isActive() &&
- importedFilter.isActive();
-
+ acceptsAllSources =
+ defaultLabelSourceFilter.isActive() && defaultFunctionSourceFilter.isActive() &&
+ importedSourceFilter.isActive() && aiSourceFilter.isActive() &&
+ analysisSourceFilter.isActive() && userDefinedSourceFilter.isActive();
acceptsAll = acceptsAllTypes && acceptsAllSources && activeAdvancedFilters.length == 0;
}
private void createFilters() {
- userDefinedFilter = new Filter("User Defined", false, false) {
- @Override
- boolean matches(Program program, Symbol symbol) {
- return symbol.getSource() == SourceType.USER_DEFINED;
- }
-
- @Override
- String getDescription() {
- return "Include Symbols named by the user.";
- }
- };
- importedFilter = new Filter("Imported", false, false) {
- @Override
- boolean matches(Program program, Symbol symbol) {
- return symbol.getSource() == SourceType.IMPORTED;
- }
-
- @Override
- String getDescription() {
- return "Include Symbols imported from external information.";
- }
- };
- analysisFilter = new Filter("Analysis", false, false) {
- @Override
- boolean matches(Program program, Symbol symbol) {
- return symbol.getSource() == SourceType.ANALYSIS;
- }
-
- @Override
- String getDescription() {
- return "Include Symbols named by auto-analysis.";
- }
- };
- defaultLabelFilter = new Filter("Default (Labels)", true, false) {
+ defaultLabelSourceFilter = new Filter("Default (Labels)", true, false) {
@Override
boolean matches(Program program, Symbol symbol) {
return symbol.getSymbolType() != SymbolType.FUNCTION &&
@@ -394,7 +371,7 @@ public class NewSymbolFilter implements SymbolFilter {
}
};
- defaultFunctionFilter = new Filter("Default (Functions)", true, false) {
+ defaultFunctionSourceFilter = new Filter("Default (Functions)", true, false) {
@Override
boolean matches(Program program, Symbol symbol) {
return symbol.getSymbolType() == SymbolType.FUNCTION &&
@@ -405,8 +382,52 @@ public class NewSymbolFilter implements SymbolFilter {
String getDescription() {
return "Include Symbols that have default names.";
}
-
};
+ aiSourceFilter = new Filter(SourceType.AI.getDisplayString(), false, false) {
+ @Override
+ boolean matches(Program program, Symbol symbol) {
+ return symbol.getSource() == SourceType.AI;
+ }
+
+ @Override
+ String getDescription() {
+ return "Include Symbols named by auto-analysis.";
+ }
+ };
+ analysisSourceFilter = new Filter(SourceType.ANALYSIS.getDisplayString(), false, false) {
+ @Override
+ boolean matches(Program program, Symbol symbol) {
+ return symbol.getSource() == SourceType.ANALYSIS;
+ }
+
+ @Override
+ String getDescription() {
+ return "Include Symbols named by auto-analysis.";
+ }
+ };
+ importedSourceFilter = new Filter(SourceType.IMPORTED.getDisplayString(), false, false) {
+ @Override
+ boolean matches(Program program, Symbol symbol) {
+ return symbol.getSource() == SourceType.IMPORTED;
+ }
+
+ @Override
+ String getDescription() {
+ return "Include Symbols imported from external information.";
+ }
+ };
+ userDefinedSourceFilter =
+ new Filter(SourceType.USER_DEFINED.getDisplayString(), false, false) {
+ @Override
+ boolean matches(Program program, Symbol symbol) {
+ return symbol.getSource() == SourceType.USER_DEFINED;
+ }
+
+ @Override
+ String getDescription() {
+ return "Include Symbols named by the user.";
+ }
+ };
Filter instructionFilter = new Filter("Instruction Labels", true, true) {
@Override
@@ -902,9 +923,7 @@ public class NewSymbolFilter implements SymbolFilter {
@Override
boolean isEnabled() {
- Iterator it = applicableFilters.iterator();
- while (it.hasNext()) {
- Filter filter = it.next();
+ for (Filter filter : applicableFilters) {
if (filter.isActive()) {
return true;
}
diff --git a/Ghidra/Features/Decompiler/src/main/help/help/topics/DecompilePlugin/DecompilerAnnotations.html b/Ghidra/Features/Decompiler/src/main/help/help/topics/DecompilePlugin/DecompilerAnnotations.html
index c9475a6a53..59ff502054 100644
--- a/Ghidra/Features/Decompiler/src/main/help/help/topics/DecompilePlugin/DecompilerAnnotations.html
+++ b/Ghidra/Features/Decompiler/src/main/help/help/topics/DecompilePlugin/DecompilerAnnotations.html
@@ -1286,6 +1286,8 @@
DEFAULT - for basic or no information
+AI - for information that is produced with AI assistance
+
ANALYSIS - for information derived by an Analyzer
IMPORTED - for information imported from an external source
diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/matchtable/SymbolTypeFilter.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/matchtable/SymbolTypeFilter.java
index 8d84929394..eeafda3403 100644
--- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/matchtable/SymbolTypeFilter.java
+++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/matchtable/SymbolTypeFilter.java
@@ -4,9 +4,9 @@
* 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.
@@ -17,6 +17,7 @@ package ghidra.feature.vt.gui.provider.matchtable;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
+import java.util.Arrays;
import javax.swing.JCheckBox;
@@ -48,6 +49,7 @@ public class SymbolTypeFilter extends CheckBoxBasedAncillaryFilter {
};
SourceType[] values = SourceType.values();
+ Arrays.sort(values, (s1, s2) -> s1.getPriority() - s2.getPriority());
for (SourceType type : values) {
GCheckBox checkBox = new GCheckBox(type.getDisplayString(), true);
checkBox.addItemListener(listener);
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/ProgramDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/ProgramDB.java
index e66d387bb8..31b9a991de 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/ProgramDB.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/ProgramDB.java
@@ -116,8 +116,10 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM
* 13-Dec-2024 - version 29 Added source file manager.
* 3-Jun-2025 - version 30 Symbol Table schema V4 with external symbol data indexing
* 15-Sep-2025 - version 31 Code Mananger dropped Composites property map use
+ * 19-Sep-2025 - version 32 Expanded number of SourceType values and record storage affecting
+ * SymbolDB, FunctionDB and RefListFlagsV0
*/
- static final int DB_VERSION = 31;
+ static final int DB_VERSION = 32;
/**
* UPGRADE_REQUIRED_BFORE_VERSION should be changed to DB_VERSION anytime the
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionAdapter.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionAdapter.java
index 0457ff2b25..983bad6685 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionAdapter.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionAdapter.java
@@ -4,9 +4,9 @@
* 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.
@@ -46,10 +46,12 @@ abstract class FunctionAdapter {
static final byte FUNCTION_INLINE_FLAG = (byte) 0x2; // Bit 1 is flag for "is inline".
static final byte FUNCTION_NO_RETURN_FLAG = (byte) 0x4; // Bit 2 is flag for "has no return".
static final byte FUNCTION_CUSTOM_PARAM_STORAGE_FLAG = (byte) 0x8; // Bit 3 is flag for "has custom storage"
- static final byte FUNCTION_SIGNATURE_SOURCE = (byte) 0x30; // Bits 4-5 are storage for "signature SourceType"
+ static final byte FUNCTION_SIGNATURE_SOURCE = (byte) 0x70; // Bits 4-6 are storage for "signature SourceType"
static final int FUNCTION_SIGNATURE_SOURCE_SHIFT = 4; // bit shift for flag storage of "signature SourceType"
+ private static final int MAX_SOURCE_VALUE = 7; // value limit based upon 3-bit storage capacity
+
final static Schema FUNCTION_SCHEMA = new Schema(CURRENT_VERSION, "ID",
new Field[] { LongField.INSTANCE, IntField.INSTANCE, IntField.INSTANCE, IntField.INSTANCE,
ByteField.INSTANCE, ByteField.INSTANCE, StringField.INSTANCE },
@@ -94,8 +96,11 @@ abstract class FunctionAdapter {
}
static byte getSignatureSourceFlagBits(SourceType signatureSource) {
- return (byte) (signatureSource
- .ordinal() << FunctionAdapter.FUNCTION_SIGNATURE_SOURCE_SHIFT);
+ int sourceTypeId = signatureSource.getStorageId();
+ if (sourceTypeId > MAX_SOURCE_VALUE) {
+ throw new RuntimeException("Unsupported SourceType storage ID: " + sourceTypeId);
+ }
+ return (byte) (sourceTypeId << FunctionAdapter.FUNCTION_SIGNATURE_SOURCE_SHIFT);
}
static FunctionAdapter findReadOnlyAdapter(DBHandle handle, AddressMap map)
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionDB.java
index 9b83a39fba..df0580546f 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionDB.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionDB.java
@@ -2445,9 +2445,9 @@ public class FunctionDB extends DatabaseObject implements Function {
SourceType getStoredSignatureSource() {
byte flags = rec.getByteValue(FunctionAdapter.FUNCTION_FLAGS_COL);
- int typeOrdinal = (flags &
+ int sourceTypeId = (flags &
FunctionAdapter.FUNCTION_SIGNATURE_SOURCE) >>> FunctionAdapter.FUNCTION_SIGNATURE_SOURCE_SHIFT;
- return SourceType.values()[typeOrdinal];
+ return SourceType.getSourceType(sourceTypeId);
}
@Override
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/references/RefListFlagsV0.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/references/RefListFlagsV0.java
index b6a523ba8b..c5712590f8 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/references/RefListFlagsV0.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/references/RefListFlagsV0.java
@@ -1,13 +1,12 @@
/* ###
* IP: GHIDRA
- * REVIEWED: YES
*
* 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.
@@ -20,13 +19,23 @@ import ghidra.program.model.symbol.SourceType;
class RefListFlagsV0 {
- private static final int SOURCE_LOBIT = 0x01;
+ // NOTE: Storage for SourceType has been expanded into upper zero-initialized bits
+ // with simple ProgramDB version change.
+
+ private static final int SOURCE_LOBIT = 0x01; // SourceType LO 1-bit
private static final int IS_PRIMARY = 0x02;
private static final int IS_OFFSET = 0x04;
private static final int HAS_SYMBOL_ID = 0x08;
private static final int IS_SHIFT = 0x10;
+ private static final int SOURCE_HIBITS = 0x60; // SourceType HI 2-bits
+
private static final int SOURCE_HIBIT = 0x20;
+ private static final int SOURCE_LOBIT_SHIFT = 0;
+ private static final int SOURCE_HIBITS_SHIFT = 5;
+
+ private static final int MAX_SOURCE_VALUE = 7; // value limit based upon 3-bit storage capacity
+
private int flags;
RefListFlagsV0(byte flags) {
@@ -36,12 +45,23 @@ class RefListFlagsV0 {
public RefListFlagsV0(boolean isPrimary, boolean isOffsetRef, boolean hasSymbolID,
boolean isShiftRef, SourceType source) {
flags = 0;
- if (source == SourceType.USER_DEFINED || source == SourceType.IMPORTED) {
- flags |= SOURCE_LOBIT;
- }
- if (source == SourceType.ANALYSIS || source == SourceType.IMPORTED) {
- flags |= SOURCE_HIBIT;
+
+ // Get the storage ID to be used to encode source type
+ // NOTE: RefListV0 uses a storage ID in some cases that differs from SourceType storage ID
+ int sourceId = switch (source) {
+ case DEFAULT -> 0;
+ case ANALYSIS -> 2;
+ default -> source.getStorageId();
+ };
+
+ // Encode SourceType value into split storage flags
+ if (sourceId > MAX_SOURCE_VALUE) {
+ throw new RuntimeException("Unsupported SourceType storage ID: " + sourceId);
}
+ int sourceTypeLoBit = (sourceId & 1) << SOURCE_LOBIT_SHIFT; // 1-bit
+ int sourceTypeHiBits = (sourceId >>> 1) << SOURCE_HIBITS_SHIFT; // remaining hi-bits
+ flags |= sourceTypeHiBits | sourceTypeLoBit;
+
if (isPrimary)
flags |= IS_PRIMARY;
if (isOffsetRef)
@@ -57,12 +77,18 @@ class RefListFlagsV0 {
}
SourceType getSource() {
- boolean isLoBit = (flags & SOURCE_LOBIT) != 0;
- boolean isHiBit = (flags & SOURCE_HIBIT) != 0;
- if (isHiBit) {
- return isLoBit ? SourceType.IMPORTED : SourceType.ANALYSIS;
- }
- return isLoBit ? SourceType.USER_DEFINED : SourceType.DEFAULT;
+
+ // Decode storage ID from flags bits
+ int sourceTypeLoBit = (flags & SOURCE_LOBIT) >>> SOURCE_LOBIT_SHIFT; // 1-bit
+ int sourceTypeHiBits = (flags & SOURCE_HIBITS) >>> (SOURCE_HIBITS_SHIFT - 1); // remaining HI-bits
+ int sourceTypeId = sourceTypeHiBits | sourceTypeLoBit;
+
+ // NOTE: RefListV0 uses a storage ID in some cases that differs from SourceType storage ID
+ return switch (sourceTypeId) {
+ case 0 -> SourceType.DEFAULT;
+ case 2 -> SourceType.ANALYSIS;
+ default -> SourceType.getSourceType(sourceTypeId);
+ };
}
public boolean hasSymbolID() {
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/MemorySymbol.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/MemorySymbol.java
index 84aae130a8..5e1601e091 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/MemorySymbol.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/MemorySymbol.java
@@ -169,7 +169,7 @@ public abstract class MemorySymbol extends SymbolDB {
newNamespace.getID());
}
if (newSource != null) {
- setSourceFlagBit(newSource);
+ setSourceFlagBits(newSource);
}
updatePinnedFlag(pinned);
updateRecord();
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/SymbolDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/SymbolDB.java
index 5d1c10dbb8..e5a9c53b20 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/SymbolDB.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/SymbolDB.java
@@ -253,7 +253,7 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
throw new IllegalArgumentException(msg);
}
if (record != null) {
- setSourceFlagBit(newSource);
+ setSourceFlagBits(newSource);
updateRecord();
symbolMgr.symbolSourceChanged(this);
}
@@ -263,10 +263,10 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
}
}
- protected void setSourceFlagBit(SourceType newSource) {
+ protected void setSourceFlagBits(SourceType newSource) {
byte flags = record.getByteValue(SymbolDatabaseAdapter.SYMBOL_FLAGS_COL);
- byte clearBits = SymbolDatabaseAdapter.SYMBOL_SOURCE_BITS;
- byte setBits = (byte) newSource.ordinal();
+ byte clearBits = SymbolDatabaseAdapter.SYMBOL_SOURCE_MASK;
+ byte setBits = SymbolDatabaseAdapter.getSourceTypeFlagsBits(newSource);
flags &= ~clearBits;
flags |= setBits;
record.setByteValue(SymbolDatabaseAdapter.SYMBOL_FLAGS_COL, flags);
@@ -280,10 +280,8 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
if (record == null) {
return SourceType.DEFAULT;
}
- byte sourceBits = SymbolDatabaseAdapter.SYMBOL_SOURCE_BITS;
byte flags = record.getByteValue(SymbolDatabaseAdapter.SYMBOL_FLAGS_COL);
- byte adapterSource = (byte) (flags & sourceBits);
- return SourceType.values()[adapterSource];
+ return SymbolDatabaseAdapter.decodeSourceTypeFromFlags(flags);
}
finally {
lock.release();
@@ -448,8 +446,8 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
private void updateSymbolSource(DBRecord symbolRecord, SourceType source) {
byte flags = record.getByteValue(SymbolDatabaseAdapter.SYMBOL_FLAGS_COL);
- flags &= ~SymbolDatabaseAdapter.SYMBOL_SOURCE_BITS;
- flags |= (byte) source.ordinal();
+ flags &= ~SymbolDatabaseAdapter.SYMBOL_SOURCE_MASK; // clear source type bits
+ flags |= SymbolDatabaseAdapter.getSourceTypeFlagsBits(source);
symbolRecord.setByteValue(SymbolDatabaseAdapter.SYMBOL_FLAGS_COL, flags);
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/SymbolDatabaseAdapter.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/SymbolDatabaseAdapter.java
index b235019df5..b9e831da77 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/SymbolDatabaseAdapter.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/SymbolDatabaseAdapter.java
@@ -56,9 +56,18 @@ abstract class SymbolDatabaseAdapter {
static final Schema SYMBOL_SCHEMA = SymbolDatabaseAdapterV4.V4_SYMBOL_SCHEMA;
- // Bits 0 & 1 are used for the source of the symbol.
- static final byte SYMBOL_SOURCE_BITS = (byte) 0x3;
+ // Bits 0, 1 and 3 are used for the source of the symbol.
+ // NOTE: On the next V5 adapter revision the source type bits should be made contiguous
+ static final byte SYMBOL_SOURCE_LO_BITS = (byte) 0x3; // bits 0-1 of SourceType storage ID
static final byte SYMBOL_PINNED_FLAG = (byte) 0x4; // Bit 2 is flag for "anchored to address".
+ static final byte SYMBOL_SOURCE_HI_BIT = (byte) 0x8; // bit-3 of SourceType storage ID
+
+ static final byte SYMBOL_SOURCE_MASK = (byte) 0xB; // (01011) Storage mask for SourceType storage ID
+
+ static final int SYMBOL_SOURCE_LO_BITS_SHIFT = 0;
+ static final int SYMBOL_SOURCE_HI_BIT_SHIFT = 3;
+
+ static final int MAX_SOURCE_VALUE = 7; // value limit based upon 3-bit storage capacity
// Symbol type constants
static final int SYMBOL_TYPE_LABEL = SymbolType.LABEL.getID();
@@ -219,6 +228,34 @@ abstract class SymbolDatabaseAdapter {
}
}
+ /**
+ * Transforms source type storage ID to V4 flag bits.
+ * @param sourceType source type
+ * @return storage ID flag bits
+ */
+ static byte getSourceTypeFlagsBits(SourceType sourceType) {
+ // Encode SourceType value into split storage flags
+ int sourceTypeId = sourceType.getStorageId();
+ if (sourceTypeId > MAX_SOURCE_VALUE) {
+ throw new RuntimeException("Unsupported SourceType storage ID: " + sourceTypeId);
+ }
+ int sourceTypeLoBits = (sourceTypeId & 0x3) << SYMBOL_SOURCE_LO_BITS_SHIFT; // bits 0-1
+ int sourceTypeHiBit = (sourceTypeId >>> 2) << SYMBOL_SOURCE_HI_BIT_SHIFT; // remaining hi-bit
+ return (byte) (sourceTypeHiBit | sourceTypeLoBits);
+ }
+
+ /**
+ * Decode V4 flags source type
+ * @param flags symbol flags
+ * @return source type
+ */
+ static SourceType decodeSourceTypeFromFlags(byte flags) {
+ int sourceTypeLoBits = (flags & SYMBOL_SOURCE_LO_BITS) >>> SYMBOL_SOURCE_LO_BITS_SHIFT; // bits 0-1
+ int sourceTypeHiBit = (flags & SYMBOL_SOURCE_HI_BIT) >>> (SYMBOL_SOURCE_HI_BIT_SHIFT - 2); // remaining HI-bit
+ int sourceTypeId = sourceTypeHiBit | sourceTypeLoBits;
+ return SourceType.getSourceType(sourceTypeId);
+ }
+
/**
* Instantiate a new basic symbol record. Caller is responsible for updating any related
* optional record fields and then adding to the table via the
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/SymbolDatabaseAdapterV4.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/SymbolDatabaseAdapterV4.java
index 9a00e883c6..82276b74f1 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/SymbolDatabaseAdapterV4.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/SymbolDatabaseAdapterV4.java
@@ -97,7 +97,7 @@ class SymbolDatabaseAdapterV4 extends SymbolDatabaseAdapter {
// if (nextID == 0) {
// nextID++;
// }
-// return createSymbol(nextID, name, address, namespaceID, symbolType, (byte) source.ordinal(),
+// return createSymbol(nextID, name, address, namespaceID, symbolType, (byte) source.getStorageId(),
// isPrimary);
// }
@@ -119,7 +119,7 @@ class SymbolDatabaseAdapterV4 extends SymbolDatabaseAdapter {
rec.setLongValue(SYMBOL_ADDR_COL, addressKey);
rec.setLongValue(SYMBOL_PARENT_ID_COL, namespaceID);
rec.setByteValue(SYMBOL_TYPE_COL, symbolType.getID());
- rec.setByteValue(SYMBOL_FLAGS_COL, (byte) source.ordinal());
+ rec.setByteValue(SYMBOL_FLAGS_COL, getSourceTypeFlagsBits(source)); // assume non-pinned
// Sparse columns - these columns don't apply to all symbols.
// they default to null unless specifically set. Null values don't consume space.
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/symbol/SourceType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/symbol/SourceType.java
index 186039e71b..0e6b4f12f4 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/symbol/SourceType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/symbol/SourceType.java
@@ -15,28 +15,83 @@
*/
package ghidra.program.model.symbol;
-public enum SourceType {
- // WARNING WARNING: do not change the order of these enums as they are stored in the
- // database by their ordinal.
+import java.util.NoSuchElementException;
+
+public enum SourceType {
+ // WARNING WARNING: the assigned storage IDs are used for persistent serialization.
+ // Any change or re-use must consider data upgrade concerns.
+
+ // The SourceType's defined below are ordered based upon their priority values.
+ // Priority values may be changed.
- /** The object's source indicator for an auto analysis. */
- ANALYSIS("Analysis", 2),
- /** The object's source indicator for a user defined. */
- USER_DEFINED("User Defined", 4),
/** The object's source indicator for a default. */
- DEFAULT("Default", 1),
+ DEFAULT("Default", 1, 2),
+ /** The object's source indicator for an auto analysis. */
+ ANALYSIS("Analysis", 2, 0),
+ /** The object's source indicator for something that was produced with AI assistance. */
+ AI("AI", 2, 4),
/** The object's source indicator for an imported. */
- IMPORTED("Imported", 3);
+ IMPORTED("Imported", 3, 3),
+ /** The object's source indicator for a user defined. */
+ USER_DEFINED("User Defined", 4, 1);
+
+ // SourceType values indexed by storageID (use null for undefined IDs).
+ private static SourceType[] SOURCE_BY_STORAGE_ID =
+ new SourceType[] { ANALYSIS, USER_DEFINED, DEFAULT, IMPORTED, AI };
private final String displayString;
- private final int priority; // bigger numbers are higher priorty
+ private final int storageId;
+ private final int priority; // bigger numbers are higher priority
- private SourceType(String displayString, int priority) {
+ /**
+ * {@link SourceType} constructor
+ * @param displayString enum display name
+ * @param priority unique priority among other defined enum values
+ * @param storageId non-negative storage ID for persistent serialization. Once an ID is
+ * assigned it may never be removed without serious consideration to DB upgrade transformation.
+ */
+ private SourceType(String displayString, int priority, int storageId) {
this.displayString = displayString;
+ this.storageId = storageId;
this.priority = priority;
}
- /** Returns a user-friendly string */
+ /**
+ * Get the SourceType which corresponds to the specified storage ID.
+ * @param storageId storage ID
+ * @return SourceType
+ * @throws NoSuchElementException if specified storage ID is not defined.
+ */
+ public static SourceType getSourceType(int storageId) {
+ try {
+ SourceType source = SOURCE_BY_STORAGE_ID[storageId];
+ if (source != null) {
+ return source;
+ }
+ }
+ catch (ArrayIndexOutOfBoundsException e) {
+ // throw error below
+ }
+ throw new NoSuchElementException("SourceType storgae ID not defined: " + storageId);
+ }
+
+ /**
+ * {@return numeric priority relative to other SourceType. Higher numbers are higher priority.}
+ */
+ public int getPriority() {
+ return priority;
+ }
+
+ /**
+ * {@return the storage ID which should be used for persistent serialization}
+ */
+ public int getStorageId() {
+ return storageId;
+ }
+
+ /**
+ * {@return a user-friendly string}
+ */
public String getDisplayString() {
return displayString;
}