Details
Diff Detail
- Build Status
Buildable 6875 Build 6875: arc lint + arc unit
Event Timeline
llvm/include/llvm/Object/WindowsResource.h | ||
---|---|---|
53–61 | I don't think we need to propagate these Error values out of the function. The constructor should assert that HeaderBytes is a good size, and at that point none of the reads can fail and you can just return the values instead of taking them by reference. | |
118 | You can just say = default; | |
119 | No need to explicitly initialize Name, its default constructor will get invoked implicitly. | |
120 | Same as above, but this time for ID, and you can initialize Name directly I believe. Name(NameRef) | |
185 | Can you do an inline initialization here? uint16_t ID = 0xFFFF; | |
llvm/lib/Object/WindowsResource.cpp | ||
96–98 | Instead of doing this seeking and reading on every function call, can you just initialize all these values in the constructor and then just return them? It makes the logic simpler to follow if you just read everything out all at once, because then there's no seeking going on. It's just read / read / read / read. |
llvm/include/llvm/Object/WindowsResource.h | ||
---|---|---|
51–54 | I'd move this out of namespace llvm as namespaces have no effect on C macros. | |
55 | isString -> IsString | |
116 | Move function definitions for this class to the .cpp file. | |
123–124 | (You want to add newlines between multi-line inline functions so that they don't look like a single blob of some code.) | |
137 | This is a question not only for this but for all the other functions you added in this patch. Can you do error checking only when you are reading files? Currently, you are doing error checking both when reading files and writing to files. However, as long as you verify that input files, and you don't generate malformed data in your code (if it does, it is a bug), you don't need to check for errors when you are writing. The reason why I'm saying is because the code is not easy to read because that contains probably too much error checking snippets. Other file reading/writing tools don't have this much ErrorOr or Expected internally, so they can be reduced. |
Move implementation to source file, removed a lot of unnecessary error checking.
llvm/include/llvm/Object/WindowsResource.h | ||
---|---|---|
51–54 | I moved it to the source file since it is no longer necessary in header. | |
55 | returns bool instead of Error now | |
137 | All the error checking is now done when the file is initially read. | |
185 | What is the purpose of this initialization? We only ever check the ID if it is in the IDChildren list, and before adding to this list we always give the ID that was written in the .res file. |
llvm/include/llvm/Object/WindowsResource.h | ||
---|---|---|
185 | You were already initializing it in the constructor to -1, but the initialization was repeated each time there was a new overload of the constructor. If you initialize it this way, it's functionally equivalent to the code you had before, but you're just not repeating the specification of the value -1. |
llvm/include/llvm/Object/WindowsResource.h | ||
---|---|---|
185 | Ah okay. I actually decided we don't really need to initialize the numeric ID. |
llvm/include/llvm/Object/WindowsResource.h | ||
---|---|---|
113 | Should this function be const? | |
124 | Can this argument be a StringRef? | |
llvm/lib/Object/WindowsResource.cpp | ||
98 | I think this function would be a lot clearer if we had some structs that we could just read out in one or two lines rather than reading some fields, ignoring others, skipping sometimes, reading sometimes, etc. How about this? class ResourceEntryRef { struct HeaderPrefix { ulittle32_t DataSize; ulittle32_t HeaderSize; ulittle16_t Unknown; ulittle16_t TypeID; ulittle16_t IDFlag; ulittle16_t NameID; }; struct HeaderSuffix { ulittle32_t DataVersion; ulittle16_t MemoryFlags; ulittle16_t LanguageID; ulittle32_t Version; ulittle32_t Characteristics; }; const HeaderPrefix *Prefix = nullptr; const HeaderSuffix *Suffix = nullptr; }; ... Error ResourceEntryRef::loadNext() { RETURN_IF_ERROR(Reader.readObject(Prefix)); if (Prefix->IDFlag != 0xFFFF) { Reader.setOffset(Reader.getOffset() - 4); RETURN_IF_ERROR(Reader.readWideString(Name)); } RETURN_IF_ERROR(Reader.readObject(Suffix)); RETURN_IF_ERROR(Reader.readArray(Data, Prefix->DataSize); RETURN_IF_ERROR(Reader.padToAlignment(sizeof(uint32_t)); return Error::success(); } | |
111 | Is this math actually necessary? It sounds like we just want to read until the first null terminator. Maybe add a function to BinaryStreamReader similar to readCString but called readWideString? | |
171–174 | Can you try this? StringChildren.emplace(NameString, std::move(NewChild)); |
Read some header entries into struct instead of reading individually.
Create readWideString function in BinaryStreamReader.
Be able to read user-defined types and add test case for this.
llvm/lib/Object/WindowsResource.cpp | ||
---|---|---|
98 | Hmmm this issue is actually pretty difficult because we can't really use a HeaderPrefix structure at all. I didn't realize this when I first implemented this but actually both the Type and the Name can either be numeric IDs or variable length strings; therefore there isn't really any "standard" length that we can read into a structure easily. Perhaps we can have a HeaderSuffix structure though.... |
llvm/lib/Object/WindowsResource.cpp | ||
---|---|---|
98 | I see. In that case, can you add a function Error ResourceEntryRef::readStringOrId(BinaryStreamReader &Reader, uint16_t &ID, ArrayRef<UTF16> &Str); and then write: RETURN_IF_ERROR(readStringOrId(Reader, TypeID, Type)); RETURN_IF_ERROR(readStringOrId(Reader, NameID, Name)); |
llvm/lib/Object/WindowsResource.cpp | ||
---|---|---|
98 | Okay. I feel like this function shouldn't be a member function of ResourceEntryRef because it only really has a use in this specific instance and it's precondition is that the offset of the reader has been directed to a specific point. |
I'd move this out of namespace llvm as namespaces have no effect on C macros.