diff --git a/Ghidra/Features/Base/src/test/java/ghidra/app/util/cparser/CParserTest.java b/Ghidra/Features/Base/src/test/java/ghidra/app/util/cparser/CParserTest.java
index 30534e0d9b..e3b0058727 100644
--- a/Ghidra/Features/Base/src/test/java/ghidra/app/util/cparser/CParserTest.java
+++ b/Ghidra/Features/Base/src/test/java/ghidra/app/util/cparser/CParserTest.java
@@ -36,10 +36,6 @@ public class CParserTest extends AbstractGhidraHeadlessIntegrationTest {
super();
}
- /**
- * This method just tries to parse a bunch o'
- * data types just checking for stack traces.
- */
@Test
public void testSimple() throws Exception {
CParser parser = new CParser();
@@ -68,10 +64,6 @@ public class CParserTest extends AbstractGhidraHeadlessIntegrationTest {
assertEquals(comp.getDataType().getName(),"char");
}
- /**
- * This method just tries to parse a bunch o'
- * data types just checking for stack traces.
- */
@Test
public void testLongLong() throws Exception {
CParser parser;
@@ -96,6 +88,27 @@ public class CParserTest extends AbstractGhidraHeadlessIntegrationTest {
assertEquals(8, pdt32.getLength());
}
+ @Test
+ public void testTypedef() throws Exception {
+ CParser parser;
+
+ parser = new CParser();
+ DataType tdDt = parser.parse("typedef struct foo * foo;");
+
+ assertTrue(tdDt != null);
+ assertTrue(tdDt instanceof TypeDef);
+ System.out.println(tdDt.getPathName());
+ System.out.println(((TypeDef)tdDt).getDataType().getPathName());
+ assertEquals("foo", tdDt.getName());
+ assertEquals("foo.conflict *", ((TypeDef)tdDt).getDataType().getName());
+ assertEquals(4, tdDt.getLength());
+
+ DataType dt = parser.getDataTypeManager().getDataType("/foo");
+ assertTrue(dt != null);
+ assertTrue(dt instanceof TypeDef);
+
+ }
+
@Test
public void testWcharT() throws Exception {
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeManagerDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeManagerDB.java
index bbb429b9c5..d70f68f7f3 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeManagerDB.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeManagerDB.java
@@ -1445,6 +1445,8 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
*
* NOTE: The original datatype name will be returned unchanged for pointers and arrays since
* they cannot be renamed.
+ *
+ * NOTE: Otherwise, if category does not exist the non-conflict name will be returned.
*
* @param path the category path of the category where the new data type live in
* the data type manager.
@@ -1452,16 +1454,39 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
* @return the unused conflict name
*/
public String getUnusedConflictName(CategoryPath path, DataType dt) {
- String name = dt.getName();
if ((dt instanceof Array) || (dt instanceof Pointer) || (dt instanceof BuiltInDataType)) {
// name not used - anything will do
- return name;
+ return dt.getName();
}
+ return getUnusedConflictName(getCategory(path), dt);
+ }
+ /**
+ * This method gets a ".conflict" name that is not currently used by any data
+ * types in the indicated category within this data type manager. If the baseName without
+ * conflict suffix is not used that name will be returned.
+ *
+ * NOTE: The original datatype name will be returned unchanged for pointers and arrays since
+ * they cannot be renamed.
+ *
+ * NOTE: Otherwise, if category does not exist the non-conflict name will be returned.
+ *
+ * @param cat the existing category to check.
+ * @param dt datatype who name is used to establish non-conflict base name
+ * @return the unused conflict name
+ */
+ private String getUnusedConflictName(Category cat, DataType dt) {
+ if ((dt instanceof Array) || (dt instanceof Pointer) || (dt instanceof BuiltInDataType)) {
+ // name not used - anything will do
+ return dt.getName();
+ }
String baseName = DataTypeUtilities.getNameWithoutConflict(dt);
+ if (cat == null) {
+ return baseName;
+ }
String testName = baseName;
int count = 0;
- while (getDataType(path, testName) != null) {
+ while (cat.getDataType(testName) != null) {
testName = baseName + DataType.CONFLICT_SUFFIX;
if (count > 0) {
testName += Integer.toString(count);
@@ -3116,6 +3141,10 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
flags = (short) TypedefDBAdapter.TYPEDEF_FLAG_AUTONAME;
cat = getCategory(dataType.getCategoryPath()); // force category
}
+ else if (cat.getDataType(name) != null) {
+ // force use of conflict name if needed
+ name = getUnusedConflictName(cat, typedef);
+ }
DBRecord record = typedefAdapter.createRecord(getID(dataType), name, flags, cat.getID(),
sourceArchiveIdValue, universalIdValue, typedef.getLastChangeTime());
TypedefDB typedefDB = new TypedefDB(this, dtCache, typedefAdapter, record);
diff --git a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/database/data/TypedefDBTest.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/database/data/TypedefDBTest.java
new file mode 100644
index 0000000000..ff3a5dc935
--- /dev/null
+++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/database/data/TypedefDBTest.java
@@ -0,0 +1,69 @@
+/* ###
+ * IP: GHIDRA
+ *
+ * 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 ghidra.program.database.data;
+
+import static org.junit.Assert.*;
+
+import org.junit.*;
+
+import generic.test.AbstractGenericTest;
+import ghidra.program.model.data.*;
+
+public class TypedefDBTest extends AbstractGenericTest {
+
+ private final String NAME = "Test";
+
+ private DataTypeManagerDB dataMgr;
+ private int txId;
+
+ @Before
+ public void setUp() throws Exception {
+ dataMgr = new StandAloneDataTypeManager("dummyDTM");
+ txId = dataMgr.startTransaction("Test");
+ }
+
+ @After
+ public void tearDown() {
+ if (txId > 0) {
+ dataMgr.endTransaction(txId, true);
+ dataMgr.close();
+ }
+ }
+
+ @Test
+ public void testDuplicateNameResolve() throws Exception {
+
+ Structure struct = new StructureDataType(NAME, 0);
+ struct.add(new ByteDataType(), "field1", "Comment1");
+ struct.add(new WordDataType(), null, "Comment2");
+ struct.add(new DWordDataType(), "field3", null);
+ struct.add(new ByteDataType(), "field4", "Comment4");
+
+ Pointer structPtr = new PointerDataType(struct);
+
+ TypeDef typeDef = new TypedefDataType(NAME, structPtr);
+
+ TypeDef td = (TypeDef) dataMgr.resolve(typeDef, null);
+ assertNotNull(td);
+ assertEquals(NAME + ".conflict", td.getName());
+
+ assertTrue(td.isEquivalent(typeDef));
+
+ assertEquals("typedef Test.conflict Test *", td.toString());
+
+ }
+
+}